From 33ec8185a63569417e9b2b7edd71aab9643ec8c3 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 14:41:53 -0400 Subject: [PATCH 01/73] feat(auto): declare Android Auto notification capability --- app/src/gplay/AndroidManifest.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index ee962f64dbe..0842bf6bbbb 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -24,6 +24,11 @@ + + + From 9a84e5fed581f9a7c30b43881f802412d06cf838 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 14:42:02 -0400 Subject: [PATCH 02/73] feat(auto): add Android Auto app descriptor --- app/src/gplay/res/xml/automotive_app_desc.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 app/src/gplay/res/xml/automotive_app_desc.xml diff --git a/app/src/gplay/res/xml/automotive_app_desc.xml b/app/src/gplay/res/xml/automotive_app_desc.xml new file mode 100644 index 00000000000..b8023ff7bdf --- /dev/null +++ b/app/src/gplay/res/xml/automotive_app_desc.xml @@ -0,0 +1,12 @@ + + + + + + From 3c35e4f09f8cce7e1e421c4dcca9e658bd9ef0a5 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 14:59:27 -0400 Subject: [PATCH 03/73] ci(auto): add one-shot PR 6012 import --- .../workflows/android-auto-import-pr6012.yml | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/android-auto-import-pr6012.yml diff --git a/.github/workflows/android-auto-import-pr6012.yml b/.github/workflows/android-auto-import-pr6012.yml new file mode 100644 index 00000000000..55f6445c3fa --- /dev/null +++ b/.github/workflows/android-auto-import-pr6012.yml @@ -0,0 +1,58 @@ +name: Android Auto - import upstream messaging support + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-import-pr6012.yml + +permissions: + contents: write + +jobs: + import-pr6012: + runs-on: ubuntu-latest + steps: + - name: Check out Android Auto branch + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: android-auto + + - name: Import nextcloud/talk-android PR 6012 as a three-way patch + shell: bash + run: | + set -euo pipefail + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + + # The fork shares Git objects with upstream, and this branch was created + # directly from the upstream PR head so the exact source is preserved. + git fetch origin upstream-pr-6012:refs/remotes/origin/upstream-pr-6012 + + PR_BASE="b846aa4fc6467b24bad60e7f347b708dcad793e9" + PR_HEAD="origin/upstream-pr-6012" + + git diff --binary "$PR_BASE".."$PR_HEAD" -- \ + SETUP.md \ + app/src/main/AndroidManifest.xml \ + app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ + app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt \ + app/src/main/res/xml/automotive_app_desc.xml \ + > /tmp/pr6012.patch + + if ! git apply --3way --index /tmp/pr6012.patch; then + echo "::error::PR 6012 still has unresolved three-way conflicts. No changes will be pushed." + git status --short + exit 1 + fi + + if git diff --cached --quiet; then + echo "PR 6012 changes are already present; nothing to commit." + exit 0 + fi + + git commit -m "feat(auto): import upstream Android Auto messaging support" + git push origin HEAD:android-auto From 5af798b96b979640383805dbf941ed344686b6b4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 18:59:43 +0000 Subject: [PATCH 04/73] feat(auto): import upstream Android Auto messaging support --- SETUP.md | 13 ++ app/src/main/AndroidManifest.xml | 26 ++- .../nextcloud/talk/jobs/NotificationWorker.kt | 205 +++++++++++------- .../nextcloud/talk/utils/NotificationUtils.kt | 34 ++- app/src/main/res/xml/automotive_app_desc.xml | 11 + 5 files changed, 204 insertions(+), 85 deletions(-) create mode 100644 app/src/main/res/xml/automotive_app_desc.xml diff --git a/SETUP.md b/SETUP.md index 540fca71af6..14aab913bdf 100644 --- a/SETUP.md +++ b/SETUP.md @@ -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: diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 54182da11ba..5260266902f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -100,7 +100,11 @@ + android:value="10"/> + + - - - - - + + + + + + newStyle.addMessage( + NotificationCompat.MessagingStyle.Message( + message.text, + message.timestamp, + message.person ) + ) + } + + val message = NotificationCompat.MessagingStyle.Message( + pushMessage.text, + pushMessage.timestamp, + sender + ) + if (imageUri != null) { + message.setData(imageMimeType ?: "image/*", imageUri) + } + newStyle.addMessage(message) + notificationBuilder.setStyle(newStyle) + } + + private fun loadSenderAvatar(notificationUser: NotificationUser?): Bitmap? { + val userType = notificationUser?.type + if (userType != "user" && userType != "guest") return null + + val baseUrl = user.baseUrl + val avatarUrl = if ("user" == userType) { + ApiUtils.getUrlForAvatar( + baseUrl!!, + notificationUser.id, + false, + darkMode = DisplayUtils.isDarkModeOn(context!!) + ) + } else { + ApiUtils.getUrlForGuestAvatar(baseUrl!!, notificationUser.name, false) } + return NotificationUtils.loadAvatarBitmapSync(avatarUrl, context!!) } private fun loadImageBitmapSync(imageUrl: String): Bitmap? { @@ -839,42 +913,43 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor return bitmap } - private fun styleChatNotification( - notificationBuilder: NotificationCompat.Builder, - activeStatusBarNotification: StatusBarNotification? - ) { + private fun pushConversationShortcut(notificationBuilder: NotificationCompat.Builder, avatarBitmap: Bitmap?) { val notificationUser = pushMessage.notificationUser ?: return + val roomToken = pushMessage.id ?: return - val userType = notificationUser.type - var style: NotificationCompat.MessagingStyle? = null - if (activeStatusBarNotification != null) { - style = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification( - activeStatusBarNotification.notification - ) - } - val person = Person.Builder() + val shortcutId = "conversation_${user.id}_$roomToken" + + val personBuilder = Person.Builder() .setKey(user.id.toString() + "@" + notificationUser.id) .setName(EmojiCompat.get().process(notificationUser.name!!)) - .setBot("bot" == userType) - if ("user" == userType || "guest" == userType) { - val baseUrl = user.baseUrl - val avatarUrl = if ("user" == userType) { - ApiUtils.getUrlForAvatar( - baseUrl!!, - notificationUser.id, - false, - darkMode = DisplayUtils.isDarkModeOn(context!!) - ) - } else { - ApiUtils.getUrlForGuestAvatar(baseUrl!!, notificationUser.name, false) - } - person.setIcon(loadAvatarSync(avatarUrl, context!!)) + if (avatarBitmap != null) { + personBuilder.setIcon(IconCompat.createWithBitmap(avatarBitmap)) + } + + val intent = Intent(context, MainActivity::class.java).apply { + action = Intent.ACTION_VIEW + putExtra(KEY_ROOM_TOKEN, roomToken) + putExtra(KEY_INTERNAL_USER_ID, user.id) } - notificationBuilder.setStyle(getStyle(person.build(), style)) + + val shortcut = ShortcutInfoCompat.Builder(context!!, shortcutId) + .setShortLabel(pushMessage.subject.ifEmpty { notificationUser.name ?: "Chat" }) + .setLongLived(true) + .setIntent(intent) + .setPerson(personBuilder.build()) + .build() + + ShortcutManagerCompat.pushDynamicShortcut(context!!, shortcut) + notificationBuilder.setShortcutId(shortcutId) } - private fun buildIntentForAction(cls: Class<*>, systemNotificationId: Int, messageId: Int): PendingIntent { + private fun buildIntentForAction( + cls: Class<*>, + systemNotificationId: Int, + messageId: Int, + mutable: Boolean = false + ): PendingIntent { val actualIntent = Intent(context, cls) // NOTE - systemNotificationId is an internal ID used on the device only. @@ -885,7 +960,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor actualIntent.putExtra(KEY_MESSAGE_ID, messageId) val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + val mutabilityFlag = if (mutable) PendingIntent.FLAG_MUTABLE else PendingIntent.FLAG_IMMUTABLE + mutabilityFlag or PendingIntent.FLAG_UPDATE_CURRENT } else { PendingIntent.FLAG_UPDATE_CURRENT } @@ -904,7 +980,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val pendingIntent = buildIntentForAction( MarkAsReadReceiver::class.java, systemNotificationId, - messageId + messageId, + mutable = false ) val markAsReadAction = NotificationCompat.Action.Builder( R.drawable.ic_mark_chat_read_24px, @@ -927,7 +1004,8 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val replyPendingIntent = buildIntentForAction( DirectReplyReceiver::class.java, systemNotificationId, - 0 + 0, + mutable = true ) val replyAction = NotificationCompat.Action.Builder(R.drawable.ic_reply, replyLabel, replyPendingIntent) .setSemanticAction(NotificationCompat.Action.SEMANTIC_ACTION_REPLY) @@ -958,7 +1036,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor dismissIntent.putExtra(KEY_DISMISS_RECORDING_URL, dismissRecordingUrl) val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT } else { PendingIntent.FLAG_UPDATE_CURRENT } @@ -992,7 +1070,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor shareRecordingIntent.putExtra(KEY_ROOM_TOKEN, pushMessage.id) val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT } else { PendingIntent.FLAG_UPDATE_CURRENT } @@ -1014,25 +1092,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor notificationBuilder.addAction(shareRecordingAction) } - private fun getStyle(person: Person, style: NotificationCompat.MessagingStyle?): NotificationCompat.MessagingStyle { - val newStyle = NotificationCompat.MessagingStyle(person) - newStyle.conversationTitle = pushMessage.subject - newStyle.isGroupConversation = "one2one" != conversationType - style?.messages?.forEach( - Consumer { message: NotificationCompat.MessagingStyle.Message -> - newStyle.addMessage( - NotificationCompat.MessagingStyle.Message( - message.text, - message.timestamp, - message.person - ) - ) - } - ) - newStyle.addMessage(pushMessage.text, pushMessage.timestamp, person) - return newStyle - } - @Throws(NumberFormatException::class) private fun parseMessageId(objectId: String): Int { val objectIdParts = objectId.split("/".toRegex()).toTypedArray() @@ -1210,7 +1269,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor // See https://github.com/nextcloud/talk-android/issues/2111 val requestCode = System.currentTimeMillis().toInt() val intentFlag: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT } else { PendingIntent.FLAG_UPDATE_CURRENT } diff --git a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt index 4023b8083eb..a5a19fa41f9 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt @@ -11,12 +11,14 @@ import android.app.Notification import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context +import android.graphics.Bitmap import android.graphics.drawable.BitmapDrawable import android.media.AudioAttributes import android.net.Uri import android.service.notification.StatusBarNotification import android.text.TextUtils import android.util.Log +import androidx.core.content.FileProvider import androidx.core.graphics.drawable.IconCompat import androidx.core.net.toUri import coil.executeBlocking @@ -30,6 +32,8 @@ import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.RingtoneSettings import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.preferences.AppPreferences +import java.io.File +import java.io.FileOutputStream import java.io.IOException @Suppress("TooManyFunctions") @@ -55,6 +59,8 @@ object NotificationUtils { const val KEY_UPLOAD_GROUP = "com.nextcloud.talk.utils.KEY_UPLOAD_GROUP" const val GROUP_SUMMARY_NOTIFICATION_ID = -1 + private const val BITMAP_COMPRESSION_QUALITY = 100 + private fun createNotificationChannel( context: Context, notificationChannel: Channel, @@ -316,7 +322,12 @@ object NotificationUtils { ) fun loadAvatarSync(avatarUrl: String, context: Context): IconCompat? { - var avatarIcon: IconCompat? = null + val bitmap = loadAvatarBitmapSync(avatarUrl, context) + return bitmap?.let { IconCompat.createWithBitmap(it) } + } + + fun loadAvatarBitmapSync(avatarUrl: String, context: Context): Bitmap? { + var avatarBitmap: Bitmap? = null val request = ImageRequest.Builder(context) .data(avatarUrl) @@ -324,13 +335,11 @@ object NotificationUtils { .placeholder(R.drawable.account_circle_96dp) .target( onSuccess = { result -> - val bitmap = (result as BitmapDrawable).bitmap - avatarIcon = IconCompat.createWithBitmap(bitmap) + avatarBitmap = (result as BitmapDrawable).bitmap }, onError = { error -> error?.let { - val bitmap = (error as BitmapDrawable).bitmap - avatarIcon = IconCompat.createWithBitmap(bitmap) + avatarBitmap = (error as BitmapDrawable).bitmap } Log.w(TAG, "Can't load avatar for URL: $avatarUrl") } @@ -339,7 +348,20 @@ object NotificationUtils { context.imageLoader.executeBlocking(request) - return avatarIcon + return avatarBitmap + } + + fun saveBitmapToCache(context: Context, bitmap: Bitmap, fileName: String): Uri? { + val cacheFile = File(context.cacheDir, fileName) + return try { + FileOutputStream(cacheFile).use { out -> + bitmap.compress(Bitmap.CompressFormat.PNG, BITMAP_COMPRESSION_QUALITY, out) + } + FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID, cacheFile) + } catch (e: IOException) { + Log.e(TAG, "Failed to save bitmap to cache", e) + null + } } private data class Channel(val id: String, val name: String, val description: String, val isImportant: Boolean) diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml new file mode 100644 index 00000000000..3082aa4c1ed --- /dev/null +++ b/app/src/main/res/xml/automotive_app_desc.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file From dd95fbf3d994c935c8ff05f1b75a79f47c210865 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:02:06 -0400 Subject: [PATCH 05/73] ci(auto): bootstrap Car App and Telecom foundation --- .../android-auto-bootstrap-car-service.yml | 274 ++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 .github/workflows/android-auto-bootstrap-car-service.yml diff --git a/.github/workflows/android-auto-bootstrap-car-service.yml b/.github/workflows/android-auto-bootstrap-car-service.yml new file mode 100644 index 00000000000..08cb0d1abf5 --- /dev/null +++ b/.github/workflows/android-auto-bootstrap-car-service.yml @@ -0,0 +1,274 @@ +name: Android Auto - bootstrap car service + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-bootstrap-car-service.yml + +permissions: + contents: write + +jobs: + bootstrap: + runs-on: ubuntu-latest + steps: + - name: Check out Android Auto branch + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: android-auto + + - name: Add Android Auto Car App and Telecom foundation + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + from pathlib import Path + + gradle = Path('app/build.gradle.kts') + text = gradle.read_text() + anchor = 'dependencies {\n implementation("androidx.media3:media3-session:1.11.0")\n' + addition = '''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") +''' + if 'androidx.car.app:app:1.7.0' not in text: + if anchor not in text: + raise SystemExit('Could not find dependencies anchor in app/build.gradle.kts') + text = text.replace(anchor, addition, 1) + gradle.write_text(text) + + manifest = Path('app/src/gplay/AndroidManifest.xml') + text = manifest.read_text() + if 'android.permission.MANAGE_OWN_CALLS' not in text: + marker = '\n' + replacement = marker + '\n \n' + if marker not in text: + raise SystemExit('Could not find gplay manifest root') + text = text.replace(marker, replacement, 1) + + if 'androidx.car.app.minCarApiLevel' not in text: + marker = ' \n' + replacement = marker + ''' + + + +''' + if marker not in text: + raise SystemExit('Could not find gplay application metadata anchor') + text = text.replace(marker, replacement, 1) + + if '.auto.TalkCarAppService' not in text: + marker = ' + + + + + + + +''' + if marker not in text: + raise SystemExit('Could not find service anchor in gplay manifest') + text = text.replace(marker, service + marker, 1) + manifest.write_text(text) + + descriptor = Path('app/src/gplay/res/xml/automotive_app_desc.xml') + text = descriptor.read_text() + if '' not in text: + text = text.replace(' \n', ' \n \n', 1) + descriptor.write_text(text) + + service_file = Path('app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt') + service_file.parent.mkdir(parents=True, exist_ok=True) + service_file.write_text('''/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto + +import android.content.ApplicationInfo +import android.content.Intent +import androidx.car.app.CarAppService +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.Session +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.car.app.validation.HostValidator +import com.nextcloud.talk.auto.call.TalkTelecomManager + +/** Android Auto entry point for Talk messaging and calling. */ +class TalkCarAppService : CarAppService() { + override fun onCreate() { + super.onCreate() + TalkTelecomManager.get(applicationContext).registerWithTelecom() + } + + override fun createHostValidator(): HostValidator = + if ((applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + HostValidator.ALLOW_ALL_HOSTS_VALIDATOR + } else { + HostValidator.Builder(this) + .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) + .build() + } + + override fun onCreateSession(): Session = TalkCarSession() +} + +private class TalkCarSession : Session() { + override fun onCreateScreen(intent: Intent): Screen = TalkCarHomeScreen(carContext) +} + +private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + val items = ItemList.Builder() + .addItem( + Row.Builder() + .setTitle("Messages") + .addText("Read, reply to, and start Talk conversations") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Messages", + "Android Auto messaging notifications and voice replies are enabled. " + + "Conversation history and contact selection are being wired to Talk next." + ) + ) + } + .build() + ) + .addItem( + Row.Builder() + .setTitle("Calls") + .addText("Start and control Talk voice calls") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Calls", + "Talk is registered with Android Telecom. " + + "The next layer connects Telecom callbacks to Talk WebRTC calls." + ) + ) + } + .build() + ) + .build() + + return ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.APP_ICON) + .setTitle("Nextcloud Talk") + .build() + ) + .setSingleList(items) + .build() + } +} + +private class TalkCarStatusScreen( + carContext: CarContext, + private val title: String, + private val status: String +) : Screen(carContext) { + override fun onGetTemplate(): Template = + ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.BACK) + .setTitle(title) + .build() + ) + .setSingleList( + ItemList.Builder() + .addItem(Row.Builder().setTitle(status).build()) + .build() + ) + .build() +} +''') + + telecom_file = Path('app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt') + telecom_file.parent.mkdir(parents=True, exist_ok=True) + telecom_file.write_text('''/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto.call + +import android.content.Context +import androidx.core.telecom.CallsManager + +/** + * Owns Talk's Core-Telecom registration for the Android Auto capable build. + * + * Call sessions will be added here as the existing Talk WebRTC lifecycle is + * bridged into Telecom. Registration is intentionally idempotent. + */ +class TalkTelecomManager private constructor(context: Context) { + val callsManager = CallsManager(context.applicationContext) + + @Volatile + private var registered = false + + @Synchronized + fun registerWithTelecom() { + if (registered) return + + val capabilities = + CallsManager.CAPABILITY_BASELINE or CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING + callsManager.registerAppWithTelecom(capabilities) + registered = true + } + + companion object { + @Volatile + private var instance: TalkTelecomManager? = null + + fun get(context: Context): TalkTelecomManager = + instance ?: synchronized(this) { + instance ?: TalkTelecomManager(context).also { instance = it } + } + } +} +''') + PY + + - name: Compile Google Play Android Auto sources + run: ./gradlew :app:compileGplayDebugKotlin --stacktrace + + - name: Commit bootstrap + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/build.gradle.kts app/src/gplay + if git diff --cached --quiet; then + echo "Bootstrap is already present." + exit 0 + fi + git commit -m "feat(auto): add Car App and Telecom foundation" + git push origin HEAD:android-auto From 867bd8a119e6e383aae369a698c867d6218c827b Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:04:18 -0400 Subject: [PATCH 06/73] tools(auto): add idempotent Car App bootstrap --- tools/android_auto_bootstrap.py | 238 ++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 tools/android_auto_bootstrap.py diff --git a/tools/android_auto_bootstrap.py b/tools/android_auto_bootstrap.py new file mode 100644 index 00000000000..88859da4aed --- /dev/null +++ b/tools/android_auto_bootstrap.py @@ -0,0 +1,238 @@ +# SPDX-FileCopyrightText: 2026 Michael Avery +# SPDX-License-Identifier: GPL-3.0-or-later + +"""Idempotently add the Android Auto Car App + Core-Telecom foundation.""" + +from pathlib import Path + + +def replace_once(text: str, old: str, new: str, description: str) -> str: + if old not in text: + raise RuntimeError(f"Could not find {description}") + return text.replace(old, new, 1) + + +gradle = Path("app/build.gradle.kts") +text = gradle.read_text() +if "androidx.car.app:app:1.7.0" not in text: + anchor = 'dependencies {\n implementation("androidx.media3:media3-session:1.11.0")\n' + addition = '''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") +''' + text = replace_once(text, anchor, addition, "dependencies anchor") + gradle.write_text(text) + +manifest = Path("app/src/gplay/AndroidManifest.xml") +text = manifest.read_text() +if "android.permission.MANAGE_OWN_CALLS" not in text: + marker = '\n' + text = replace_once( + text, + marker, + marker + '\n \n', + "gplay manifest root", + ) + +if "androidx.car.app.minCarApiLevel" not in text: + marker = ' \n' + addition = ''' + + + +''' + text = replace_once(text, marker, marker + addition, "gplay application metadata") + +if ".auto.TalkCarAppService" not in text: + marker = ' + + + + + + + +''' + text = replace_once(text, marker, service + marker, "gplay service anchor") +manifest.write_text(text) + +descriptor = Path("app/src/gplay/res/xml/automotive_app_desc.xml") +text = descriptor.read_text() +if '' not in text: + text = replace_once( + text, + ' \n', + ' \n \n', + "Android Auto notification capability", + ) + descriptor.write_text(text) + +service_file = Path("app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt") +service_file.parent.mkdir(parents=True, exist_ok=True) +if not service_file.exists(): + service_file.write_text('''/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto + +import android.content.ApplicationInfo +import android.content.Intent +import androidx.car.app.CarAppService +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.Session +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.car.app.validation.HostValidator +import com.nextcloud.talk.auto.call.TalkTelecomManager + +/** Android Auto entry point for Talk messaging and calling. */ +class TalkCarAppService : CarAppService() { + override fun onCreate() { + super.onCreate() + TalkTelecomManager.get(applicationContext).registerWithTelecom() + } + + override fun createHostValidator(): HostValidator = + if ((applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + HostValidator.ALLOW_ALL_HOSTS_VALIDATOR + } else { + HostValidator.Builder(this) + .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) + .build() + } + + override fun onCreateSession(): Session = TalkCarSession() +} + +private class TalkCarSession : Session() { + override fun onCreateScreen(intent: Intent): Screen = TalkCarHomeScreen(carContext) +} + +private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + val items = ItemList.Builder() + .addItem( + Row.Builder() + .setTitle("Messages") + .addText("Read, reply to, and start Talk conversations") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Messages", + "Messaging notifications and voice replies are enabled. " + + "Conversation history and contact selection are the next layer." + ) + ) + } + .build() + ) + .addItem( + Row.Builder() + .setTitle("Calls") + .addText("Start and control Talk voice calls") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Calls", + "Talk is registered with Android Telecom. " + + "The next layer connects Telecom callbacks to Talk WebRTC calls." + ) + ) + } + .build() + ) + .build() + + return ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.APP_ICON) + .setTitle("Nextcloud Talk") + .build() + ) + .setSingleList(items) + .build() + } +} + +private class TalkCarStatusScreen( + carContext: CarContext, + private val title: String, + private val status: String +) : Screen(carContext) { + override fun onGetTemplate(): Template = + ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.BACK) + .setTitle(title) + .build() + ) + .setSingleList( + ItemList.Builder() + .addItem(Row.Builder().setTitle(status).build()) + .build() + ) + .build() +} +''') + +telecom_file = Path("app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt") +telecom_file.parent.mkdir(parents=True, exist_ok=True) +if not telecom_file.exists(): + telecom_file.write_text('''/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto.call + +import android.content.Context +import androidx.core.telecom.CallsManager + +/** Owns Core-Telecom registration for the Android Auto capable build. */ +class TalkTelecomManager private constructor(context: Context) { + val callsManager = CallsManager(context.applicationContext) + + @Volatile + private var registered = false + + @Synchronized + fun registerWithTelecom() { + if (registered) return + val capabilities = + CallsManager.CAPABILITY_BASELINE or CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING + callsManager.registerAppWithTelecom(capabilities) + registered = true + } + + companion object { + @Volatile + private var instance: TalkTelecomManager? = null + + fun get(context: Context): TalkTelecomManager = + instance ?: synchronized(this) { + instance ?: TalkTelecomManager(context).also { instance = it } + } + } +} +''') From 129a2e18ca44475322b0648f83d77171a470829f Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:04:29 -0400 Subject: [PATCH 07/73] ci(auto): apply Car App bootstrap --- .../android-auto-apply-bootstrap.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/android-auto-apply-bootstrap.yml diff --git a/.github/workflows/android-auto-apply-bootstrap.yml b/.github/workflows/android-auto-apply-bootstrap.yml new file mode 100644 index 00000000000..0d87a77f3b3 --- /dev/null +++ b/.github/workflows/android-auto-apply-bootstrap.yml @@ -0,0 +1,37 @@ +name: Android Auto - apply bootstrap + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-apply-bootstrap.yml + +permissions: + contents: write + +jobs: + apply: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Apply Android Auto bootstrap + run: python3 tools/android_auto_bootstrap.py + + - name: Commit generated changes + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/build.gradle.kts app/src/gplay + if git diff --cached --quiet; then + echo "Bootstrap already applied." + exit 0 + fi + git commit -m "feat(auto): add Car App and Telecom foundation" + git push origin HEAD:android-auto From 0d25e2b05f26097b46036e1c53f6902ff54e7831 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:04:47 +0000 Subject: [PATCH 08/73] feat(auto): add Car App and Telecom foundation --- app/build.gradle.kts | 4 + app/src/gplay/AndroidManifest.xml | 18 +++ .../nextcloud/talk/auto/TalkCarAppService.kt | 115 ++++++++++++++++++ .../talk/auto/call/TalkTelecomManager.kt | 37 ++++++ app/src/gplay/res/xml/automotive_app_desc.xml | 1 + 5 files changed, 175 insertions(+) create mode 100644 app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt create mode 100644 app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index db8f8e673ca..a861ffc8588 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -194,6 +194,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") diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 0842bf6bbbb..1b736e49813 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -9,6 +9,8 @@ + + + + + + + + + + + + + + diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt new file mode 100644 index 00000000000..b7eb0e2b772 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt @@ -0,0 +1,115 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto + +import android.content.ApplicationInfo +import android.content.Intent +import androidx.car.app.CarAppService +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.Session +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.car.app.validation.HostValidator +import com.nextcloud.talk.auto.call.TalkTelecomManager + +/** Android Auto entry point for Talk messaging and calling. */ +class TalkCarAppService : CarAppService() { + override fun onCreate() { + super.onCreate() + TalkTelecomManager.get(applicationContext).registerWithTelecom() + } + + override fun createHostValidator(): HostValidator = + if ((applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0) { + HostValidator.ALLOW_ALL_HOSTS_VALIDATOR + } else { + HostValidator.Builder(this) + .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) + .build() + } + + override fun onCreateSession(): Session = TalkCarSession() +} + +private class TalkCarSession : Session() { + override fun onCreateScreen(intent: Intent): Screen = TalkCarHomeScreen(carContext) +} + +private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { + override fun onGetTemplate(): Template { + val items = ItemList.Builder() + .addItem( + Row.Builder() + .setTitle("Messages") + .addText("Read, reply to, and start Talk conversations") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Messages", + "Messaging notifications and voice replies are enabled. " + + "Conversation history and contact selection are the next layer." + ) + ) + } + .build() + ) + .addItem( + Row.Builder() + .setTitle("Calls") + .addText("Start and control Talk voice calls") + .setOnClickListener { + screenManager.push( + TalkCarStatusScreen( + carContext, + "Calls", + "Talk is registered with Android Telecom. " + + "The next layer connects Telecom callbacks to Talk WebRTC calls." + ) + ) + } + .build() + ) + .build() + + return ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.APP_ICON) + .setTitle("Nextcloud Talk") + .build() + ) + .setSingleList(items) + .build() + } +} + +private class TalkCarStatusScreen( + carContext: CarContext, + private val title: String, + private val status: String +) : Screen(carContext) { + override fun onGetTemplate(): Template = + ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.BACK) + .setTitle(title) + .build() + ) + .setSingleList( + ItemList.Builder() + .addItem(Row.Builder().setTitle(status).build()) + .build() + ) + .build() +} diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt new file mode 100644 index 00000000000..742ef94c585 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -0,0 +1,37 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto.call + +import android.content.Context +import androidx.core.telecom.CallsManager + +/** Owns Core-Telecom registration for the Android Auto capable build. */ +class TalkTelecomManager private constructor(context: Context) { + val callsManager = CallsManager(context.applicationContext) + + @Volatile + private var registered = false + + @Synchronized + fun registerWithTelecom() { + if (registered) return + val capabilities = + CallsManager.CAPABILITY_BASELINE or CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING + callsManager.registerAppWithTelecom(capabilities) + registered = true + } + + companion object { + @Volatile + private var instance: TalkTelecomManager? = null + + fun get(context: Context): TalkTelecomManager = + instance ?: synchronized(this) { + instance ?: TalkTelecomManager(context).also { instance = it } + } + } +} diff --git a/app/src/gplay/res/xml/automotive_app_desc.xml b/app/src/gplay/res/xml/automotive_app_desc.xml index b8023ff7bdf..1d01264c419 100644 --- a/app/src/gplay/res/xml/automotive_app_desc.xml +++ b/app/src/gplay/res/xml/automotive_app_desc.xml @@ -9,4 +9,5 @@ + From ebccc58276c101360866abcc72bddfec82bd9a77 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:05:43 -0400 Subject: [PATCH 09/73] ci(auto): add foundation compile validator --- .../android-auto-validate-foundation.yml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/android-auto-validate-foundation.yml diff --git a/.github/workflows/android-auto-validate-foundation.yml b/.github/workflows/android-auto-validate-foundation.yml new file mode 100644 index 00000000000..c2daa06b3b0 --- /dev/null +++ b/.github/workflows/android-auto-validate-foundation.yml @@ -0,0 +1,56 @@ +name: Android Auto - validate foundation + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-validate-foundation.yml + +permissions: + contents: write + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Compile gplay debug Kotlin + id: compile + shell: bash + run: | + set +e + ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-build.log 2>&1 + rc=$? + echo "rc=$rc" >> "$GITHUB_OUTPUT" + exit 0 + + - name: Record validation result + shell: bash + run: | + set -euo pipefail + rc='${{ steps.compile.outputs.rc }}' + if [ "$rc" = "0" ]; then + result="PASS" + else + result="FAIL" + fi + { + echo "# Android Auto foundation build" + echo + echo "Result: **$result**" + echo + echo '```text' + tail -n 200 /tmp/android-auto-build.log + echo '```' + } > ANDROID_AUTO_BUILD_STATUS.md + + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add ANDROID_AUTO_BUILD_STATUS.md + git commit -m "ci(auto): record foundation compile result" + git push origin HEAD:android-auto From be58d5c21549f665e349ffbfde3a2f956515e35b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:07:49 +0000 Subject: [PATCH 10/73] ci(auto): record foundation compile result --- ANDROID_AUTO_BUILD_STATUS.md | 206 +++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 ANDROID_AUTO_BUILD_STATUS.md diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md new file mode 100644 index 00000000000..5844cd0283a --- /dev/null +++ b/ANDROID_AUTO_BUILD_STATUS.md @@ -0,0 +1,206 @@ +# Android Auto foundation build + +Result: **FAIL** + +```text + at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) + at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) + at org.gradle.internal.serialize.graph.CodecKt.writeWith(Codec.kt:83) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:521) + at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor(ConfigurationCacheBuildTreeIO.kt:131) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:101) + at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor$default(ConfigurationCacheBuildTreeIO.kt:124) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheStateWithSpecialEncoders(DefaultConfigurationCacheIO.kt:368) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0$0(DefaultConfigurationCacheIO.kt:272) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withSharedObjectEncoderFor(DefaultConfigurationCacheIO.kt:331) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0(DefaultConfigurationCacheIO.kt:271) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withStringEncoderFor(DefaultConfigurationCacheIO.kt:319) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState(DefaultConfigurationCacheIO.kt:270) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeRootBuildStateTo(DefaultConfigurationCacheIO.kt:218) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.writeConfigurationCacheState(DefaultConfigurationCache.kt:803) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0$0(DefaultConfigurationCache.kt:717) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore$lambda$0(DefaultConfigurationCache.kt:732) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore$lambda$0(ConfigurationCacheRepository.kt:255) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$withExclusiveAccessToCache$1.get(ConfigurationCacheRepository.kt:321) + at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) + at org.gradle.cache.internal.DefaultCacheCoordinator.withFileLock(DefaultCacheCoordinator.java:226) + at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:148) + at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingPersistentCache.withFileLock(DefaultCacheFactory.java:245) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository.withExclusiveAccessToCache(ConfigurationCacheRepository.kt:319) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository.access$withExclusiveAccessToCache(ConfigurationCacheRepository.kt:54) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore(ConfigurationCacheRepository.kt:245) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore(DefaultConfigurationCache.kt:729) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0(DefaultConfigurationCache.kt:716) + at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt$withWorkGraphStoreOperation$1.run(ConfigurationCacheBuildOperations.kt:63) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) + at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt.withWorkGraphStoreOperation(ConfigurationCacheBuildOperations.kt:56) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph(DefaultConfigurationCache.kt:715) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1$0(DefaultConfigurationCache.kt:282) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.degradeGracefullyOr(DefaultConfigurationCache.kt:342) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1(DefaultConfigurationCache.kt:282) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runWorkThatContributesToCacheEntry(DefaultConfigurationCache.kt:654) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks(DefaultConfigurationCache.kt:279) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:57) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:56) + at org.gradle.internal.Try.ofFailable(Try.java:46) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:56) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:55) + at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:115) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:55) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$0(DefaultBuildTreeLifecycleController.java:80) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$0(DefaultBuildTreeLifecycleController.java:166) + at org.gradle.internal.model.StateTransitionController.lambda$transition$2(StateTransitionController.java:227) + at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) + at org.gradle.internal.model.StateTransitionController.lambda$transition$1(StateTransitionController.java:227) + at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) + at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:227) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:163) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:80) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:75) + at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31) + at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) + at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:55) + at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:83) + at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:118) + at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:64) + at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:97) + at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:119) + at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:97) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeLifecycle(DefaultBuildTreeActionExecutor.java:126) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.access$100(DefaultBuildTreeActionExecutor.java:52) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:98) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:94) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runAsBuildOperation(DefaultBuildTreeActionExecutor.java:94) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.lambda$runBuildTreeAction$0(DefaultBuildTreeActionExecutor.java:88) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeAction(DefaultBuildTreeActionExecutor.java:88) + at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:111) + at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64) + at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:106) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:94) + at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:73) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:67) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:45) + at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:57) + at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:32) + at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:51) + at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:39) + at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:47) + at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:31) + at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:70) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:40) + at org.gradle.internal.daemon.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:80) + at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables.doBuild(ApplyClientEnvironmentVariables.java:80) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:74) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) + at org.gradle.launcher.daemon.server.DaemonStateCoordinator.lambda$runCommand$0(DaemonStateCoordinator.java:321) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) +Caused by: org.gradle.api.internal.artifacts.verification.exceptions.DependencyVerificationException: Dependency verification failed for configuration ':app:gplayDebugCompileClasspath': + - On artifact app-1.7.0.module (androidx.car.app:app:1.7.0) in repository 'Google': Artifact was signed with key '0F06FF86BEEAF4E71866EE5232EE5355A6BC6E42' and passed verification but the key isn't in your trusted keys list. + - On artifact app-projected-1.7.0.module (androidx.car.app:app-projected:1.7.0) in repository 'Google': Artifact was signed with key '0F06FF86BEEAF4E71866EE5232EE5355A6BC6E42' and passed verification but the key isn't in your trusted keys list. + - On artifact activity-1.2.0.module (androidx.activity:activity:1.2.0) in repository 'Google': checksum is missing from verification metadata. + - On artifact core-1.7.0.module (androidx.core:core:1.7.0) in repository 'Google': checksum is missing from verification metadata. + - On artifact lifecycle-common-java8-2.2.0.pom (androidx.lifecycle:lifecycle-common-java8:2.2.0) in repository 'Google': checksum is missing from verification metadata. + - On artifact lifecycle-viewmodel-2.2.0.pom (androidx.lifecycle:lifecycle-viewmodel:2.2.0) in repository 'Google': checksum is missing from verification metadata. + +If the artifacts are trustworthy, you will need to update the gradle/verification-metadata.xml file. For more on how to do this, please refer to https://docs.gradle.org/9.7.1/userguide/dependency_verification.html#sec:troubleshooting-verification in the Gradle documentation. + +These files failed verification: + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.activity/activity/1.2.0/bf16f90bedd7c7a07e49b50855f054d7ce6d334/activity-1.2.0.module + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/2a6571ed3083306a86b878832a46e65071b90321/app-projected-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/fba5cd3d1ac1d4ca2396e2baf3d6fed27b18a0dd/app-projected-1.7.0.module.asc) + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/8ab21571b692c6c17f0671e2ee6505f3010b41d9/app-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/5cdaf21b75e7acc9c208da5d57ddec72a88b6064/app-1.7.0.module.asc) + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.core/core/1.7.0/2a8d5bf97abc192d56c1b610479c4d82ce88f086/core-1.7.0.module + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/873ea8000ab8cb7c7eb7e0a8234028bfbc16e613/lifecycle-common-java8-2.2.0.pom + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-viewmodel/2.2.0/5b85f9eedca6f1e45f62c6d3ca150cae66acf366/lifecycle-viewmodel-2.2.0.pom + +GRADLE_USER_HOME = /home/runner/.gradle + +These files failed verification: + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.activity/activity/1.2.0/bf16f90bedd7c7a07e49b50855f054d7ce6d334/activity-1.2.0.module + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/2a6571ed3083306a86b878832a46e65071b90321/app-projected-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/fba5cd3d1ac1d4ca2396e2baf3d6fed27b18a0dd/app-projected-1.7.0.module.asc) + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/8ab21571b692c6c17f0671e2ee6505f3010b41d9/app-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/5cdaf21b75e7acc9c208da5d57ddec72a88b6064/app-1.7.0.module.asc) + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.core/core/1.7.0/2a8d5bf97abc192d56c1b610479c4d82ce88f086/core-1.7.0.module + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/873ea8000ab8cb7c7eb7e0a8234028bfbc16e613/lifecycle-common-java8-2.2.0.pom + - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-viewmodel/2.2.0/5b85f9eedca6f1e45f62c6d3ca150cae66acf366/lifecycle-viewmodel-2.2.0.pom + +GRADLE_USER_HOME = /home/runner/.gradle + +Open this report for more details: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/dependency-verification/at-1787598367480/dependency-verification-report.html + at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.verification.ChecksumAndSignatureVerificationOverride.artifactsAccessed(ChecksumAndSignatureVerificationOverride.java:196) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver$1.run(ResolvedArtifactSetResolver.java:69) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.visitArtifacts(ResolvedArtifactSetResolver.java:65) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.lambda$visitInUnmanagedWorkerThread$0(ResolvedArtifactSetResolver.java:61) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsUnmanagedWorkerThread(DefaultWorkerLeaseService.java:159) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.visitInUnmanagedWorkerThread(ResolvedArtifactSetResolver.java:61) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultSelectedArtifactSet.visitArtifacts(DefaultSelectedArtifactSet.java:59) + at org.gradle.api.internal.artifacts.configurations.ResolutionResultProviderBackedSelectedArtifactSet.visitArtifacts(ResolutionResultProviderBackedSelectedArtifactSet.java:52) + at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.SelectedArtifactSet.visitFiles(SelectedArtifactSet.java:34) + at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:75) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) + at org.gradle.internal.serialize.codecs.core.CollectingVisitor.startVisit(FileCollectionCodec.kt:208) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:357) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeViaCollectingVisitor(FileCollectionCodec.kt:81) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeContents(FileCollectionCodec.kt:74) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:63) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:55) + at org.gradle.internal.serialize.graph.codecs.BindingsBackedCodec.encode(BindingsBackedCodec.kt:66) + at org.gradle.internal.serialize.graph.DefaultWriteContext.write(Contexts.kt:111) + at org.gradle.internal.serialize.graph.BeanPropertyExtensionsKt.writePropertyValue(BeanPropertyExtensions.kt:34) + ... 230 more + + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. + +BUILD FAILED in 1m 47s +Configuration cache entry discarded due to serialization error. +``` From 7d671ecc68d9060737ac2fc80246e35d7302e6b3 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:09:16 -0400 Subject: [PATCH 11/73] ci(auto): generate dependency verification metadata --- .../android-auto-update-verification.yml | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/android-auto-update-verification.yml diff --git a/.github/workflows/android-auto-update-verification.yml b/.github/workflows/android-auto-update-verification.yml new file mode 100644 index 00000000000..1304c1055e3 --- /dev/null +++ b/.github/workflows/android-auto-update-verification.yml @@ -0,0 +1,40 @@ +name: Android Auto - update dependency verification + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-update-verification.yml + +permissions: + contents: write + +jobs: + verification: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Generate verification metadata for Android Auto dependencies + shell: bash + run: | + set -euo pipefail + ./gradlew --write-verification-metadata sha256,pgp :app:compileGplayDebugKotlin --stacktrace + + - name: Commit verification metadata + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add gradle/verification-metadata.xml gradle/verification-keyring.keys 2>/dev/null || true + if git diff --cached --quiet; then + echo "No verification metadata changes were necessary." + exit 0 + fi + git commit -m "build(auto): trust AndroidX Car dependencies" + git push origin HEAD:android-auto From f8f3ebeefa0dbf3de0279a952dcadd220d8e1860 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:12:12 -0400 Subject: [PATCH 12/73] ci(auto): resolve verification metadata before compile --- .github/workflows/android-auto-update-verification.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android-auto-update-verification.yml b/.github/workflows/android-auto-update-verification.yml index 1304c1055e3..d715490fc26 100644 --- a/.github/workflows/android-auto-update-verification.yml +++ b/.github/workflows/android-auto-update-verification.yml @@ -23,7 +23,13 @@ jobs: shell: bash run: | set -euo pipefail - ./gradlew --write-verification-metadata sha256,pgp :app:compileGplayDebugKotlin --stacktrace + # Resolve the GPlay compile classpath without compiling sources. This lets + # Gradle write the new trusted signatures/checksums even if source code + # still needs a later compile fix. + ./gradlew :app:dependencies \ + --configuration gplayDebugCompileClasspath \ + --write-verification-metadata sha256,pgp \ + --stacktrace - name: Commit verification metadata shell: bash From 50c3743446344d9c86737868aa386ba6ca4db609 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:13:48 -0400 Subject: [PATCH 13/73] ci(auto): narrowly verify AndroidX Car dependencies --- .../android-auto-fix-verification.yml | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/android-auto-fix-verification.yml diff --git a/.github/workflows/android-auto-fix-verification.yml b/.github/workflows/android-auto-fix-verification.yml new file mode 100644 index 00000000000..2cda7341fc4 --- /dev/null +++ b/.github/workflows/android-auto-fix-verification.yml @@ -0,0 +1,68 @@ +name: Android Auto - fix dependency verification + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-fix-verification.yml + +permissions: + contents: write + +jobs: + fix-verification: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Trust Google's AndroidX Car signing key for Car App artifacts + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + from pathlib import Path + + p = Path('gradle/verification-metadata.xml') + text = p.read_text() + key = '' + car = ' ' + if car not in text: + if key not in text: + raise SystemExit('Expected Google AndroidX trusted key was not found') + text = text.replace(key, key + '\n' + car, 1) + p.write_text(text) + PY + + - name: Record checksums for newly resolved transitive metadata + shell: bash + run: | + # --write-verification-metadata is allowed to discover and write the exact + # SHA-256 entries required by this classpath. Commit whatever it writes even + # if dependency reporting itself returns non-zero. + set +e + ./gradlew :app:dependencies \ + --configuration gplayDebugCompileClasspath \ + --write-verification-metadata sha256 \ + --stacktrace + echo "Gradle dependency resolution exit code: $?" + exit 0 + + - name: Commit verification update + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add gradle/verification-metadata.xml + if git diff --cached --quiet; then + echo "Verification metadata already complete." + exit 0 + fi + git commit -m "build(auto): verify AndroidX Car dependencies" + git fetch origin android-auto + git rebase origin/android-auto + git push origin HEAD:android-auto From fcc5750c02cac50c54b0360b243f5b0a11eff77b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:16:55 +0000 Subject: [PATCH 14/73] build(auto): verify AndroidX Car dependencies --- gradle/verification-metadata.xml | 1358 ++++++++++++++++++++++++++++++ 1 file changed, 1358 insertions(+) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 2ebe711fe95..f2db9714063 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -64,6 +64,7 @@ + @@ -570,6 +571,11 @@ + + + + + @@ -818,6 +824,11 @@ + + + + + @@ -945,6 +956,14 @@ + + + + + + + + @@ -993,6 +1012,14 @@ + + + + + + + + @@ -1417,6 +1444,22 @@ + + + + + + + + + + + + + + + + @@ -1706,6 +1749,11 @@ + + + + + @@ -1716,6 +1764,11 @@ + + + + + @@ -1749,6 +1802,11 @@ + + + + + @@ -1842,6 +1900,14 @@ + + + + + + + + @@ -1920,6 +1986,11 @@ + + + + + @@ -2018,6 +2089,14 @@ + + + + + + + + @@ -2096,6 +2175,11 @@ + + + + + @@ -2192,6 +2276,14 @@ + + + + + + + + @@ -2273,6 +2365,11 @@ + + + + + @@ -2369,6 +2466,14 @@ + + + + + + + + @@ -2654,6 +2759,11 @@ + + + + + @@ -2742,6 +2852,14 @@ + + + + + + + + @@ -2881,6 +2999,11 @@ + + + + + @@ -2977,6 +3100,14 @@ + + + + + + + + @@ -3058,6 +3189,11 @@ + + + + + @@ -3122,6 +3258,14 @@ + + + + + + + + @@ -3171,6 +3315,11 @@ + + + + + @@ -3219,6 +3368,14 @@ + + + + + + + + @@ -3257,6 +3414,11 @@ + + + + + @@ -3363,6 +3525,14 @@ + + + + + + + + @@ -3452,6 +3622,11 @@ + + + + + @@ -3553,6 +3728,14 @@ + + + + + + + + @@ -3639,6 +3822,11 @@ + + + + + @@ -3735,6 +3923,14 @@ + + + + + + + + @@ -3816,6 +4012,11 @@ + + + + + @@ -3917,6 +4118,14 @@ + + + + + + + + @@ -4003,6 +4212,11 @@ + + + + + @@ -4099,6 +4313,14 @@ + + + + + + + + @@ -4180,6 +4402,11 @@ + + + + + @@ -4276,6 +4503,14 @@ + + + + + + + + @@ -4372,6 +4607,14 @@ + + + + + + + + @@ -4458,6 +4701,11 @@ + + + + + @@ -4559,6 +4807,14 @@ + + + + + + + + @@ -4642,6 +4898,11 @@ + + + + + @@ -4725,6 +4986,14 @@ + + + + + + + + @@ -4808,6 +5077,11 @@ + + + + + @@ -4891,6 +5165,14 @@ + + + + + + + + @@ -4977,6 +5259,11 @@ + + + + + @@ -5078,6 +5365,14 @@ + + + + + + + + @@ -5164,6 +5459,11 @@ + + + + + @@ -5260,6 +5560,14 @@ + + + + + + + + @@ -5341,6 +5649,11 @@ + + + + + @@ -5437,6 +5750,14 @@ + + + + + + + + @@ -5559,6 +5880,14 @@ + + + + + + + + @@ -5583,6 +5912,14 @@ + + + + + + + + @@ -5692,6 +6029,11 @@ + + + + + @@ -5774,6 +6116,14 @@ + + + + + + + + @@ -5966,6 +6316,14 @@ + + + + + + + + @@ -6110,6 +6468,14 @@ + + + + + + + + @@ -6254,6 +6620,14 @@ + + + + + + + + @@ -7323,6 +7697,11 @@ + + + + + @@ -8088,6 +8467,16 @@ + + + + + + + + + + @@ -8155,6 +8544,11 @@ + + + + + @@ -8579,6 +8973,14 @@ + + + + + + + + @@ -8675,6 +9077,14 @@ + + + + + + + + @@ -8771,6 +9181,14 @@ + + + + + + + + @@ -8867,6 +9285,14 @@ + + + + + + + + @@ -8963,6 +9389,14 @@ + + + + + + + + @@ -9043,6 +9477,14 @@ + + + + + + + + @@ -9059,6 +9501,14 @@ + + + + + + + + @@ -9155,6 +9605,14 @@ + + + + + + + + @@ -9251,11 +9709,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -9272,6 +9754,14 @@ + + + + + + + + @@ -10334,6 +10824,11 @@ + + + + + @@ -10366,6 +10861,14 @@ + + + + + + + + @@ -10411,6 +10914,11 @@ + + + + + @@ -10443,6 +10951,14 @@ + + + + + + + + @@ -11562,6 +12078,14 @@ + + + + + + + + @@ -11706,6 +12230,14 @@ + + + + + + + + @@ -11850,6 +12382,14 @@ + + + + + + + + @@ -11860,6 +12400,11 @@ + + + + + @@ -12100,6 +12645,14 @@ + + + + + + + + @@ -12244,6 +12797,14 @@ + + + + + + + + @@ -12388,6 +12949,14 @@ + + + + + + + + @@ -12436,6 +13005,14 @@ + + + + + + + + @@ -12580,6 +13157,14 @@ + + + + + + + + @@ -12724,6 +13309,14 @@ + + + + + + + + @@ -12868,6 +13461,14 @@ + + + + + + + + @@ -13012,6 +13613,14 @@ + + + + + + + + @@ -13156,6 +13765,14 @@ + + + + + + + + @@ -13300,6 +13917,14 @@ + + + + + + + + @@ -13444,6 +14069,14 @@ + + + + + + + + @@ -13700,6 +14333,14 @@ + + + + + + + + @@ -13844,6 +14485,14 @@ + + + + + + + + @@ -13988,6 +14637,14 @@ + + + + + + + + @@ -14132,6 +14789,14 @@ + + + + + + + + @@ -14276,6 +14941,14 @@ + + + + + + + + @@ -14420,6 +15093,14 @@ + + + + + + + + @@ -14564,6 +15245,14 @@ + + + + + + + + @@ -14788,6 +15477,14 @@ + + + + + + + + @@ -14948,6 +15645,14 @@ + + + + + + + + @@ -14980,6 +15685,14 @@ + + + + + + + + @@ -14996,6 +15709,14 @@ + + + + + + + + @@ -15156,6 +15877,14 @@ + + + + + + + + @@ -15316,6 +16045,14 @@ + + + + + + + + @@ -15484,6 +16221,14 @@ + + + + + + + + @@ -15628,6 +16373,14 @@ + + + + + + + + @@ -15676,6 +16429,14 @@ + + + + + + + + @@ -15724,6 +16485,14 @@ + + + + + + + + @@ -15772,6 +16541,14 @@ + + + + + + + + @@ -15916,6 +16693,14 @@ + + + + + + + + @@ -15964,6 +16749,14 @@ + + + + + + + + @@ -16012,6 +16805,14 @@ + + + + + + + + @@ -16060,6 +16861,14 @@ + + + + + + + + @@ -16108,6 +16917,14 @@ + + + + + + + + @@ -16252,6 +17069,14 @@ + + + + + + + + @@ -16396,6 +17221,14 @@ + + + + + + + + @@ -16540,6 +17373,14 @@ + + + + + + + + @@ -16684,6 +17525,14 @@ + + + + + + + + @@ -17244,6 +18093,14 @@ + + + + + + + + @@ -17388,6 +18245,14 @@ + + + + + + + + @@ -17532,6 +18397,14 @@ + + + + + + + + @@ -17676,6 +18549,14 @@ + + + + + + + + @@ -17820,6 +18701,14 @@ + + + + + + + + @@ -17964,6 +18853,14 @@ + + + + + + + + @@ -18108,6 +19005,14 @@ + + + + + + + + @@ -18252,6 +19157,14 @@ + + + + + + + + @@ -18396,6 +19309,14 @@ + + + + + + + + @@ -18540,6 +19461,14 @@ + + + + + + + + @@ -18684,6 +19613,14 @@ + + + + + + + + @@ -18828,6 +19765,14 @@ + + + + + + + + @@ -19116,6 +20061,14 @@ + + + + + + + + @@ -19260,6 +20213,14 @@ + + + + + + + + @@ -19276,6 +20237,14 @@ + + + + + + + + @@ -19292,6 +20261,14 @@ + + + + + + + + @@ -19436,6 +20413,14 @@ + + + + + + + + @@ -19539,6 +20524,11 @@ + + + + + @@ -20387,6 +21377,14 @@ + + + + + + + + @@ -20419,6 +21417,14 @@ + + + + + + + + @@ -20555,6 +21561,14 @@ + + + + + + + + @@ -20717,6 +21731,14 @@ + + + + + + + + @@ -20781,6 +21803,14 @@ + + + + + + + + @@ -21306,6 +22336,11 @@ + + + + + @@ -21620,6 +22655,14 @@ + + + + + + + + @@ -21652,6 +22695,14 @@ + + + + + + + + @@ -21818,6 +22869,9 @@ + + + @@ -21942,6 +22996,14 @@ + + + + + + + + @@ -22420,6 +23482,14 @@ + + + + + + + + @@ -22529,6 +23599,14 @@ + + + + + + + + @@ -22613,6 +23691,11 @@ + + + + + @@ -22689,6 +23772,9 @@ + + + @@ -22704,6 +23790,14 @@ + + + + + + + + @@ -22719,6 +23813,11 @@ + + + + + @@ -22744,6 +23843,16 @@ + + + + + + + + + + @@ -22754,6 +23863,21 @@ + + + + + + + + + + + + + + + @@ -22800,6 +23924,14 @@ + + + + + + + + @@ -22885,6 +24017,11 @@ + + + + + @@ -22935,6 +24072,14 @@ + + + + + + + + @@ -23044,6 +24189,11 @@ + + + + + @@ -25494,6 +26644,14 @@ + + + + + + + + @@ -25759,6 +26917,14 @@ + + + + + + + + @@ -26631,6 +27797,14 @@ + + + + + + + + @@ -26639,6 +27813,14 @@ + + + + + + + + @@ -26858,6 +28040,7 @@ + @@ -26959,6 +28142,11 @@ + + + + + @@ -26969,6 +28157,11 @@ + + + + + @@ -26994,6 +28187,11 @@ + + + + + @@ -27004,11 +28202,21 @@ + + + + + + + + + + @@ -27022,6 +28230,14 @@ + + + + + + + + @@ -27035,6 +28251,11 @@ + + + + + @@ -27045,6 +28266,11 @@ + + + + + @@ -27075,6 +28301,11 @@ + + + + + @@ -27085,6 +28316,11 @@ + + + + + @@ -27095,6 +28331,11 @@ + + + + + @@ -27147,6 +28388,11 @@ + + + + + @@ -27157,6 +28403,11 @@ + + + + + @@ -27177,6 +28428,11 @@ + + + + + @@ -27187,6 +28443,11 @@ + + + + + @@ -27197,6 +28458,11 @@ + + + + + @@ -31349,6 +32615,11 @@ + + + + + @@ -31512,6 +32783,11 @@ + + + + + @@ -32238,6 +33514,14 @@ + + + + + + + + @@ -32342,6 +33626,14 @@ + + + + + + + + @@ -32446,6 +33738,14 @@ + + + + + + + + @@ -32486,6 +33786,14 @@ + + + + + + + + @@ -32590,6 +33898,14 @@ + + + + + + + + @@ -32622,6 +33938,11 @@ + + + + + @@ -32638,6 +33959,14 @@ + + + + + + + + @@ -32648,6 +33977,11 @@ + + + + + @@ -32664,6 +33998,14 @@ + + + + + + + + @@ -32697,6 +34039,14 @@ + + + + + + + + @@ -33916,6 +35266,14 @@ + + + + + + + + From 677aed0595babdfdddffd7387b472aba2d76517e Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:18:05 -0400 Subject: [PATCH 15/73] ci(auto): validate Android Auto source changes --- .../workflows/android-auto-validate-foundation.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android-auto-validate-foundation.yml b/.github/workflows/android-auto-validate-foundation.yml index c2daa06b3b0..cd0d7d894f6 100644 --- a/.github/workflows/android-auto-validate-foundation.yml +++ b/.github/workflows/android-auto-validate-foundation.yml @@ -6,6 +6,9 @@ on: - android-auto paths: - .github/workflows/android-auto-validate-foundation.yml + - app/build.gradle.kts + - app/src/gplay/** + - gradle/verification-metadata.xml permissions: contents: write @@ -24,7 +27,7 @@ jobs: shell: bash run: | set +e - ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-build.log 2>&1 + ./gradlew :app:compileGplayDebugKotlin --no-configuration-cache --stacktrace > /tmp/android-auto-build.log 2>&1 rc=$? echo "rc=$rc" >> "$GITHUB_OUTPUT" exit 0 @@ -45,12 +48,18 @@ jobs: echo "Result: **$result**" echo echo '```text' - tail -n 200 /tmp/android-auto-build.log + tail -n 250 /tmp/android-auto-build.log echo '```' } > ANDROID_AUTO_BUILD_STATUS.md git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git add ANDROID_AUTO_BUILD_STATUS.md + if git diff --cached --quiet; then + echo "Validation result is unchanged." + exit 0 + fi git commit -m "ci(auto): record foundation compile result" + git fetch origin android-auto + git rebase origin/android-auto git push origin HEAD:android-auto From c1d85b0249bcacc4eaf08028c6b77945b43f5f49 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:19:00 -0400 Subject: [PATCH 16/73] feat(auto): add flavor-neutral call interop bridge --- .../nextcloud/talk/call/TalkCallInterop.kt | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt diff --git a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt new file mode 100644 index 00000000000..4f1910765a7 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt @@ -0,0 +1,112 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.call + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN + +/** + * Flavor-neutral bridge between Talk's WebRTC call lifecycle and optional + * platform call integrations such as Core-Telecom in the Google Play flavor. + * + * The broadcasts are package-restricted, so they never leave this app. On a + * flavor without a platform integration receiver they are harmless no-ops. + */ +object TalkCallInterop { + const val ACTION_INCOMING_CALL = "com.nextcloud.talk.call.action.INCOMING" + const val ACTION_CALL_STARTED = "com.nextcloud.talk.call.action.STARTED" + const val ACTION_CALL_ACTIVE = "com.nextcloud.talk.call.action.ACTIVE" + const val ACTION_CALL_ENDED = "com.nextcloud.talk.call.action.ENDED" + + const val ACTION_CONTROL_DISCONNECT = "com.nextcloud.talk.call.action.CONTROL_DISCONNECT" + const val ACTION_CONTROL_MUTE = "com.nextcloud.talk.call.action.CONTROL_MUTE" + + const val EXTRA_CALL_KEY = "talk_call_key" + const val EXTRA_CALL_EXTRAS = "talk_call_extras" + const val EXTRA_DISPLAY_NAME = "talk_display_name" + const val EXTRA_INCOMING = "talk_incoming" + const val EXTRA_VIDEO = "talk_video" + const val EXTRA_MUTED = "talk_muted" + + fun callKey(accountId: Long, roomToken: String): String = "$accountId@$roomToken" + + fun notifyIncomingCall( + context: Context, + callExtras: Bundle, + displayName: String, + video: Boolean + ) { + val accountId = callExtras.getLong(KEY_INTERNAL_USER_ID, -1L) + val roomToken = callExtras.getString(KEY_ROOM_TOKEN).orEmpty() + if (accountId < 0L || roomToken.isBlank()) return + + send( + context, + Intent(ACTION_INCOMING_CALL) + .putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken)) + .putExtra(EXTRA_CALL_EXTRAS, Bundle(callExtras)) + .putExtra(EXTRA_DISPLAY_NAME, displayName) + .putExtra(EXTRA_INCOMING, true) + .putExtra(EXTRA_VIDEO, video) + ) + } + + fun notifyCallStarted( + context: Context, + accountId: Long, + roomToken: String, + displayName: String, + incoming: Boolean, + video: Boolean, + callExtras: Bundle + ) { + if (accountId < 0L || roomToken.isBlank()) return + send( + context, + Intent(ACTION_CALL_STARTED) + .putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken)) + .putExtra(EXTRA_CALL_EXTRAS, Bundle(callExtras)) + .putExtra(EXTRA_DISPLAY_NAME, displayName) + .putExtra(EXTRA_INCOMING, incoming) + .putExtra(EXTRA_VIDEO, video) + ) + } + + fun notifyCallActive(context: Context, accountId: Long, roomToken: String) { + notifySimple(context, ACTION_CALL_ACTIVE, accountId, roomToken) + } + + fun notifyCallEnded(context: Context, accountId: Long, roomToken: String) { + notifySimple(context, ACTION_CALL_ENDED, accountId, roomToken) + } + + fun requestDisconnect(context: Context, callKey: String) { + send(context, Intent(ACTION_CONTROL_DISCONNECT).putExtra(EXTRA_CALL_KEY, callKey)) + } + + fun requestMute(context: Context, callKey: String, muted: Boolean) { + send( + context, + Intent(ACTION_CONTROL_MUTE) + .putExtra(EXTRA_CALL_KEY, callKey) + .putExtra(EXTRA_MUTED, muted) + ) + } + + private fun notifySimple(context: Context, action: String, accountId: Long, roomToken: String) { + if (accountId < 0L || roomToken.isBlank()) return + send(context, Intent(action).putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken))) + } + + private fun send(context: Context, intent: Intent) { + intent.setPackage(context.packageName) + context.sendBroadcast(intent) + } +} From 631a27b5d850d6baf4567813e976c8cb3054ba41 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:19:48 -0400 Subject: [PATCH 17/73] feat(auto): bridge Talk calls into Core-Telecom --- .../talk/auto/call/TalkTelecomManager.kt | 209 +++++++++++++++++- 1 file changed, 207 insertions(+), 2 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index 742ef94c585..aa74ba40e34 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -7,11 +7,39 @@ package com.nextcloud.talk.auto.call import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.telecom.DisconnectCause +import android.util.Log +import androidx.core.app.NotificationManagerCompat +import androidx.core.telecom.CallAttributesCompat +import androidx.core.telecom.CallControlScope import androidx.core.telecom.CallsManager +import com.nextcloud.talk.activities.CallActivity +import com.nextcloud.talk.call.TalkCallInterop +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_TIMESTAMP +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.launch +import java.util.concurrent.ConcurrentHashMap -/** Owns Core-Telecom registration for the Android Auto capable build. */ +/** + * Bridges Talk's existing WebRTC calls into Core-Telecom so Android Auto and + * other system call surfaces can control them. + * + * This class does not own media/signaling. It only mirrors call state and + * translates Telecom requests into package-local Talk call controls. + */ class TalkTelecomManager private constructor(context: Context) { - val callsManager = CallsManager(context.applicationContext) + private val appContext = context.applicationContext + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + private val callsManager = CallsManager(appContext) + private val calls = ConcurrentHashMap() @Volatile private var registered = false @@ -25,7 +53,184 @@ class TalkTelecomManager private constructor(context: Context) { registered = true } + fun onIncomingCall( + callKey: String, + callExtras: Bundle, + displayName: String, + video: Boolean + ) { + addCallIfNeeded( + callKey = callKey, + callExtras = callExtras, + displayName = displayName, + incoming = true, + video = video, + activityStarted = false + ) + } + + fun onCallStarted( + callKey: String, + callExtras: Bundle, + displayName: String, + incoming: Boolean, + video: Boolean + ) { + val existing = calls[callKey] + if (existing != null) { + existing.activityStarted = true + existing.callExtras = Bundle(callExtras) + existing.control?.let { control -> scope.launch { control.setActive() } } + return + } + + addCallIfNeeded( + callKey = callKey, + callExtras = callExtras, + displayName = displayName, + incoming = incoming, + video = video, + activityStarted = true + ) + } + + fun onCallActive(callKey: String) { + calls[callKey]?.control?.let { control -> scope.launch { control.setActive() } } + } + + fun onCallEnded(callKey: String) { + val managed = calls.remove(callKey) ?: return + managed.control?.let { control -> + scope.launch { + runCatching { + control.disconnect(DisconnectCause(DisconnectCause.LOCAL)) + }.onFailure { Log.w(TAG, "Telecom disconnect failed for $callKey", it) } + } + } + } + + private fun addCallIfNeeded( + callKey: String, + callExtras: Bundle, + displayName: String, + incoming: Boolean, + video: Boolean, + activityStarted: Boolean + ) { + if (callKey.isBlank() || calls.containsKey(callKey)) return + registerWithTelecom() + + val managed = ManagedCall( + callKey = callKey, + callExtras = Bundle(callExtras), + displayName = displayName.ifBlank { "Nextcloud Talk" }, + incoming = incoming, + video = video, + activityStarted = activityStarted + ) + if (calls.putIfAbsent(callKey, managed) != null) return + + scope.launch { + try { + val roomToken = managed.callExtras.getString(KEY_ROOM_TOKEN).orEmpty() + val attributes = CallAttributesCompat( + displayName = managed.displayName, + address = Uri.parse("sip:${Uri.encode(roomToken)}@nextcloud-talk"), + direction = if (managed.incoming) { + CallAttributesCompat.DIRECTION_INCOMING + } else { + CallAttributesCompat.DIRECTION_OUTGOING + }, + callType = if (managed.video) { + CallAttributesCompat.CALL_TYPE_VIDEO_CALL + } else { + CallAttributesCompat.CALL_TYPE_AUDIO_CALL + }, + // Talk does not currently expose a true hold operation that stops + // both microphone and incoming media, so don't advertise hold yet. + callCapabilities = 0 + ) + + callsManager.addCall( + callAttributes = attributes, + onAnswer = { requestedCallType -> + launchTalkCall( + managed, + voiceOnly = requestedCallType != CallAttributesCompat.CALL_TYPE_VIDEO_CALL + ) + }, + onDisconnect = { + cancelIncomingNotification(managed) + TalkCallInterop.requestDisconnect(appContext, managed.callKey) + }, + onSetActive = { + if (!managed.activityStarted) { + launchTalkCall(managed, voiceOnly = !managed.video) + } + }, + onSetInactive = { + // We intentionally do not advertise hold. If Telecom must make + // the call inactive (for example for a cellular call), ending + // Talk is safer than leaving WebRTC media active in the car. + TalkCallInterop.requestDisconnect(appContext, managed.callKey) + } + ) { + managed.control = this + + scope.launch { + isMuted + .distinctUntilChanged() + .collect { muted -> + TalkCallInterop.requestMute(appContext, managed.callKey, muted) + } + } + + if (!managed.incoming || managed.activityStarted) { + scope.launch { setActive() } + } + } + } catch (t: Throwable) { + calls.remove(callKey) + Log.e(TAG, "Unable to add Talk call to Telecom: $callKey", t) + } + } + } + + private fun launchTalkCall(managed: ManagedCall, voiceOnly: Boolean) { + managed.activityStarted = true + cancelIncomingNotification(managed) + + val extras = Bundle(managed.callExtras).apply { + putBoolean(KEY_CALL_VOICE_ONLY, voiceOnly) + } + appContext.startActivity( + Intent(appContext, CallActivity::class.java).apply { + putExtras(extras) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + ) + } + + private fun cancelIncomingNotification(managed: ManagedCall) { + val notificationId = managed.callExtras.getInt(KEY_NOTIFICATION_TIMESTAMP, 0) + if (notificationId != 0) { + NotificationManagerCompat.from(appContext).cancel(notificationId) + } + } + + private data class ManagedCall( + val callKey: String, + var callExtras: Bundle, + val displayName: String, + val incoming: Boolean, + val video: Boolean, + @Volatile var activityStarted: Boolean, + @Volatile var control: CallControlScope? = null + ) + companion object { + private const val TAG = "TalkTelecomManager" + @Volatile private var instance: TalkTelecomManager? = null From 0bb477b191cc0f2ea8e510e176eb21b1d7c229b2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 19:22:43 +0000 Subject: [PATCH 18/73] ci(auto): record foundation compile result --- ANDROID_AUTO_BUILD_STATUS.md | 382 ++++++++++++++++++++--------------- 1 file changed, 216 insertions(+), 166 deletions(-) diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md index 5844cd0283a..9958af714ea 100644 --- a/ANDROID_AUTO_BUILD_STATUS.md +++ b/ANDROID_AUTO_BUILD_STATUS.md @@ -3,79 +3,66 @@ Result: **FAIL** ```text - at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) - at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) - at org.gradle.internal.serialize.graph.CodecKt.writeWith(Codec.kt:83) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:521) - at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor(ConfigurationCacheBuildTreeIO.kt:131) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:101) - at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor$default(ConfigurationCacheBuildTreeIO.kt:124) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheStateWithSpecialEncoders(DefaultConfigurationCacheIO.kt:368) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0$0(DefaultConfigurationCacheIO.kt:272) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withSharedObjectEncoderFor(DefaultConfigurationCacheIO.kt:331) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0(DefaultConfigurationCacheIO.kt:271) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withStringEncoderFor(DefaultConfigurationCacheIO.kt:319) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState(DefaultConfigurationCacheIO.kt:270) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeRootBuildStateTo(DefaultConfigurationCacheIO.kt:218) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.writeConfigurationCacheState(DefaultConfigurationCache.kt:803) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0$0(DefaultConfigurationCache.kt:717) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore$lambda$0(DefaultConfigurationCache.kt:732) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore$lambda$0(ConfigurationCacheRepository.kt:255) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$withExclusiveAccessToCache$1.get(ConfigurationCacheRepository.kt:321) - at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) - at org.gradle.cache.internal.DefaultCacheCoordinator.withFileLock(DefaultCacheCoordinator.java:226) - at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:148) - at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingPersistentCache.withFileLock(DefaultCacheFactory.java:245) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository.withExclusiveAccessToCache(ConfigurationCacheRepository.kt:319) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository.access$withExclusiveAccessToCache(ConfigurationCacheRepository.kt:54) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore(ConfigurationCacheRepository.kt:245) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore(DefaultConfigurationCache.kt:729) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0(DefaultConfigurationCache.kt:716) - at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt$withWorkGraphStoreOperation$1.run(ConfigurationCacheBuildOperations.kt:63) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) +> Task :app:kaptGplayDebugKotlin +warning: The following options were not recognized by any processor: '[room.schemaLocation, kapt.kotlin.generated]' + +> Task :app:compileGplayDebugKotlin FAILED +e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:9:24 Unresolved reference 'ApplicationInfo'. +e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:32:40 Unresolved reference 'ApplicationInfo'. + +[Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html + +FAILURE: Build failed with an exception. + +* What went wrong: +Execution failed for task ':app:compileGplayDebugKotlin' (registered by plugin 'com.android.internal.application'). +> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork + > Compilation error. See log for more details + +* Try: +> Run with --info or --debug option to get more log output. +> Run with --scan to get full insights from a Build Scan (powered by Develocity). +> Get more help at https://help.gradle.org. + +* Exception is: +org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileGplayDebugKotlin' (registered by plugin 'com.android.internal.application'). + at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:135) + at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:288) + at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:133) + at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:121) + at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41) + at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) + at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) + at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) + at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) + at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) + at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) + at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) + at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) - at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt.withWorkGraphStoreOperation(ConfigurationCacheBuildOperations.kt:56) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph(DefaultConfigurationCache.kt:715) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1$0(DefaultConfigurationCache.kt:282) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.degradeGracefullyOr(DefaultConfigurationCache.kt:342) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1(DefaultConfigurationCache.kt:282) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runWorkThatContributesToCacheEntry(DefaultConfigurationCache.kt:654) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks(DefaultConfigurationCache.kt:279) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:57) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:56) - at org.gradle.internal.Try.ofFailable(Try.java:46) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:56) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:55) - at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:115) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:55) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$0(DefaultBuildTreeLifecycleController.java:80) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$0(DefaultBuildTreeLifecycleController.java:166) - at org.gradle.internal.model.StateTransitionController.lambda$transition$2(StateTransitionController.java:227) - at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) - at org.gradle.internal.model.StateTransitionController.lambda$transition$1(StateTransitionController.java:227) - at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) - at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:227) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:163) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:80) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:75) - at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31) - at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) - at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:55) - at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:83) - at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:118) - at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:64) - at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:97) - at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:119) - at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:97) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeLifecycle(DefaultBuildTreeActionExecutor.java:126) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.access$100(DefaultBuildTreeActionExecutor.java:52) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:98) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:94) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) + at org.gradle.execution.plan.DefaultNodeExecutor.executeLocalTaskNode(DefaultNodeExecutor.java:55) + at org.gradle.execution.plan.DefaultNodeExecutor.execute(DefaultNodeExecutor.java:34) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:339) + at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:339) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:328) + at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459) + at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376) + at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:111) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:146) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:131) + at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:35) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:54) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:43) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) @@ -83,90 +70,44 @@ Result: **FAIL** at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runAsBuildOperation(DefaultBuildTreeActionExecutor.java:94) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.lambda$runBuildTreeAction$0(DefaultBuildTreeActionExecutor.java:88) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:40) + at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$executeTasks$0(DefaultBuildLifecycleController.java:323) + at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) + at org.gradle.internal.model.StateTransitionController.lambda$tryTransition$0(StateTransitionController.java:235) + at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) + at org.gradle.internal.model.StateTransitionController.tryTransition(StateTransitionController.java:235) + at org.gradle.internal.build.DefaultBuildLifecycleController.executeTasks(DefaultBuildLifecycleController.java:314) + at org.gradle.internal.build.DefaultBuildWorkGraphController$DefaultBuildWorkGraph.runWork(DefaultBuildWorkGraphController.java:220) at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeAction(DefaultBuildTreeActionExecutor.java:88) - at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:111) - at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64) - at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:106) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:94) - at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:73) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:67) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:45) - at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:57) - at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:32) - at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:51) - at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:39) - at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:47) - at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:31) - at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:70) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:40) - at org.gradle.internal.daemon.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:80) - at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables.doBuild(ApplyClientEnvironmentVariables.java:80) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:74) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) - at org.gradle.launcher.daemon.server.DaemonStateCoordinator.lambda$runCommand$0(DaemonStateCoordinator.java:321) + at org.gradle.composite.internal.DefaultBuildController.doRun(DefaultBuildController.java:182) + at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.lambda$run$0(DefaultBuildController.java:199) + at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) + at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.run(DefaultBuildController.java:199) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) -Caused by: org.gradle.api.internal.artifacts.verification.exceptions.DependencyVerificationException: Dependency verification failed for configuration ':app:gplayDebugCompileClasspath': - - On artifact app-1.7.0.module (androidx.car.app:app:1.7.0) in repository 'Google': Artifact was signed with key '0F06FF86BEEAF4E71866EE5232EE5355A6BC6E42' and passed verification but the key isn't in your trusted keys list. - - On artifact app-projected-1.7.0.module (androidx.car.app:app-projected:1.7.0) in repository 'Google': Artifact was signed with key '0F06FF86BEEAF4E71866EE5232EE5355A6BC6E42' and passed verification but the key isn't in your trusted keys list. - - On artifact activity-1.2.0.module (androidx.activity:activity:1.2.0) in repository 'Google': checksum is missing from verification metadata. - - On artifact core-1.7.0.module (androidx.core:core:1.7.0) in repository 'Google': checksum is missing from verification metadata. - - On artifact lifecycle-common-java8-2.2.0.pom (androidx.lifecycle:lifecycle-common-java8:2.2.0) in repository 'Google': checksum is missing from verification metadata. - - On artifact lifecycle-viewmodel-2.2.0.pom (androidx.lifecycle:lifecycle-viewmodel:2.2.0) in repository 'Google': checksum is missing from verification metadata. - -If the artifacts are trustworthy, you will need to update the gradle/verification-metadata.xml file. For more on how to do this, please refer to https://docs.gradle.org/9.7.1/userguide/dependency_verification.html#sec:troubleshooting-verification in the Gradle documentation. - -These files failed verification: - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.activity/activity/1.2.0/bf16f90bedd7c7a07e49b50855f054d7ce6d334/activity-1.2.0.module - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/2a6571ed3083306a86b878832a46e65071b90321/app-projected-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/fba5cd3d1ac1d4ca2396e2baf3d6fed27b18a0dd/app-projected-1.7.0.module.asc) - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/8ab21571b692c6c17f0671e2ee6505f3010b41d9/app-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/5cdaf21b75e7acc9c208da5d57ddec72a88b6064/app-1.7.0.module.asc) - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.core/core/1.7.0/2a8d5bf97abc192d56c1b610479c4d82ce88f086/core-1.7.0.module - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/873ea8000ab8cb7c7eb7e0a8234028bfbc16e613/lifecycle-common-java8-2.2.0.pom - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-viewmodel/2.2.0/5b85f9eedca6f1e45f62c6d3ca150cae66acf366/lifecycle-viewmodel-2.2.0.pom - -GRADLE_USER_HOME = /home/runner/.gradle - -These files failed verification: - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.activity/activity/1.2.0/bf16f90bedd7c7a07e49b50855f054d7ce6d334/activity-1.2.0.module - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/2a6571ed3083306a86b878832a46e65071b90321/app-projected-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app-projected/1.7.0/fba5cd3d1ac1d4ca2396e2baf3d6fed27b18a0dd/app-projected-1.7.0.module.asc) - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/8ab21571b692c6c17f0671e2ee6505f3010b41d9/app-1.7.0.module (signature: GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/5cdaf21b75e7acc9c208da5d57ddec72a88b6064/app-1.7.0.module.asc) - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.core/core/1.7.0/2a8d5bf97abc192d56c1b610479c4d82ce88f086/core-1.7.0.module - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-common-java8/2.2.0/873ea8000ab8cb7c7eb7e0a8234028bfbc16e613/lifecycle-common-java8-2.2.0.pom - - GRADLE_USER_HOME/caches/modules-2/files-2.1/androidx.lifecycle/lifecycle-viewmodel/2.2.0/5b85f9eedca6f1e45f62c6d3ca150cae66acf366/lifecycle-viewmodel-2.2.0.pom - -GRADLE_USER_HOME = /home/runner/.gradle - -Open this report for more details: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/dependency-verification/at-1787598367480/dependency-verification-report.html - at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.verification.ChecksumAndSignatureVerificationOverride.artifactsAccessed(ChecksumAndSignatureVerificationOverride.java:196) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver$1.run(ResolvedArtifactSetResolver.java:69) +Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork + at org.gradle.workers.internal.DefaultWorkerExecutor$WorkItemExecution.waitForCompletion(DefaultWorkerExecutor.java:273) + at org.gradle.internal.work.DefaultAsyncWorkTracker.lambda$waitForItemsAndGatherFailures$2(DefaultAsyncWorkTracker.java:132) + at org.gradle.internal.Factories$1.create(Factories.java:30) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withoutLocksBlocking$0(DefaultWorkerLeaseService.java:412) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.withoutLocksBlocking(DefaultWorkerLeaseService.java:407) + at org.gradle.internal.work.DefaultWorkerLeaseService.blocking(DefaultWorkerLeaseService.java:257) + at org.gradle.internal.work.DefaultWorkerLeaseService.blocking(DefaultWorkerLeaseService.java:239) + at org.gradle.internal.work.DefaultAsyncWorkTracker.lambda$waitForItemsAndGatherFailures$1(DefaultAsyncWorkTracker.java:128) + at org.gradle.internal.Factories$1.create(Factories.java:30) + at org.gradle.internal.resources.AbstractResourceLockRegistry.whileDisallowingLockChanges(AbstractResourceLockRegistry.java:51) + at org.gradle.internal.work.DefaultWorkerLeaseService.whileDisallowingProjectLockChanges(DefaultWorkerLeaseService.java:262) + at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForItemsAndGatherFailures(DefaultAsyncWorkTracker.java:127) + at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForItemsAndGatherFailures(DefaultAsyncWorkTracker.java:93) + at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForAll(DefaultAsyncWorkTracker.java:79) + at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForCompletion(DefaultAsyncWorkTracker.java:67) + at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:267) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) @@ -174,25 +115,134 @@ Open this report for more details: file:///home/runner/work/Nextcloud_Talk_Andro at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.visitArtifacts(ResolvedArtifactSetResolver.java:65) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.lambda$visitInUnmanagedWorkerThread$0(ResolvedArtifactSetResolver.java:61) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsUnmanagedWorkerThread(DefaultWorkerLeaseService.java:159) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvedArtifactSetResolver.visitInUnmanagedWorkerThread(ResolvedArtifactSetResolver.java:61) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.DefaultSelectedArtifactSet.visitArtifacts(DefaultSelectedArtifactSet.java:59) - at org.gradle.api.internal.artifacts.configurations.ResolutionResultProviderBackedSelectedArtifactSet.visitArtifacts(ResolutionResultProviderBackedSelectedArtifactSet.java:52) - at org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.SelectedArtifactSet.visitFiles(SelectedArtifactSet.java:34) - at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:75) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) - at org.gradle.internal.serialize.codecs.core.CollectingVisitor.startVisit(FileCollectionCodec.kt:208) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:357) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeViaCollectingVisitor(FileCollectionCodec.kt:81) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeContents(FileCollectionCodec.kt:74) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:63) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:55) - at org.gradle.internal.serialize.graph.codecs.BindingsBackedCodec.encode(BindingsBackedCodec.kt:66) - at org.gradle.internal.serialize.graph.DefaultWriteContext.write(Contexts.kt:111) - at org.gradle.internal.serialize.graph.BeanPropertyExtensionsKt.writePropertyValue(BeanPropertyExtensions.kt:34) - ... 230 more + at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:244) + at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:227) + at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:210) + at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:176) + at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:167) + at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:47) + at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:137) + at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:134) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:134) + at org.gradle.internal.execution.steps.ExecuteStep$Mutable.execute(ExecuteStep.java:80) + at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:42) + at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:75) + at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) + at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:51) + at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:29) + at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.executeMutable(RemovePreviousOutputsStep.java:67) + at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.executeMutable(RemovePreviousOutputsStep.java:39) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:42) + at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:24) + at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:69) + at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:46) + at org.gradle.internal.execution.steps.ResolveInputChangesStep.executeMutable(ResolveInputChangesStep.java:39) + at org.gradle.internal.execution.steps.ResolveInputChangesStep.executeMutable(ResolveInputChangesStep.java:28) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189) + at org.gradle.internal.execution.steps.BuildCacheStep.executeAndStoreInCache(BuildCacheStep.java:145) + at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$3(BuildCacheStep.java:104) + at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$1(BuildCacheStep.java:104) + at org.gradle.internal.Try$Success.map(Try.java:170) + at org.gradle.internal.execution.steps.BuildCacheStep.executeWithCache(BuildCacheStep.java:88) + at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$0(BuildCacheStep.java:75) + at org.gradle.internal.Either$Left.fold(Either.java:116) + at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62) + at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:74) + at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:49) + at org.gradle.internal.execution.steps.StoreExecutionStateStep.executeMutable(StoreExecutionStateStep.java:46) + at org.gradle.internal.execution.steps.StoreExecutionStateStep.executeMutable(StoreExecutionStateStep.java:35) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:75) + at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:53) + at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:53) + at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:35) + at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) + at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) + at org.gradle.internal.execution.steps.ResolveMutableCachingStateStep.executeDelegate(ResolveMutableCachingStateStep.java:70) + at org.gradle.internal.execution.steps.ResolveMutableCachingStateStep.executeDelegate(ResolveMutableCachingStateStep.java:32) + at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:69) + at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:37) + at org.gradle.internal.execution.steps.ResolveChangesStep.executeMutable(ResolveChangesStep.java:63) + at org.gradle.internal.execution.steps.ResolveChangesStep.executeMutable(ResolveChangesStep.java:34) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.ValidateStep$Mutable.executeDelegate(ValidateStep.java:79) + at org.gradle.internal.execution.steps.ValidateStep$Mutable.executeDelegate(ValidateStep.java:65) + at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:105) + at org.gradle.internal.execution.steps.ValidateStep$Mutable.execute(ValidateStep.java:65) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.executeMutable(CaptureMutableStateBeforeExecutionStep.java:86) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:65) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:45) + at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeWithNonEmptySources(SkipEmptyMutableWorkStep.java:210) + at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:90) + at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:53) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) + at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.executeMutable(LoadPreviousExecutionStateStep.java:36) + at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.executeMutable(LoadPreviousExecutionStateStep.java:23) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.HandleStaleOutputsStep.executeMutable(HandleStaleOutputsStep.java:77) + at org.gradle.internal.execution.steps.HandleStaleOutputsStep.executeMutable(HandleStaleOutputsStep.java:43) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$executeMutable$0(AssignMutableWorkspaceStep.java:34) + at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:305) + at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.executeMutable(AssignMutableWorkspaceStep.java:30) + at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.executeMutable(AssignMutableWorkspaceStep.java:21) + at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) + at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40) + at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23) + at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67) + at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67) + at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39) + at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46) + at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34) + at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:56) + at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:38) + at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:68) + at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:132) + ... 61 more +Caused by: org.jetbrains.kotlin.gradle.tasks.CompilationErrorException: Compilation error. See log for more details + at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.throwExceptionIfCompilationFailed(tasksUtils.kt:21) + at org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork.execute(BuildToolsApiCompilationWork.kt:320) + at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61) + at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:103) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) + at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) + at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58) + at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$1(DefaultWorkerExecutor.java:169) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:191) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$600(DefaultConditionalExecutionQueue.java:112) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:168) + at org.gradle.internal.Factories$1.create(Factories.java:30) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:137) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:163) + at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:125) + ... 2 more Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. @@ -201,6 +251,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 1m 47s -Configuration cache entry discarded due to serialization error. +BUILD FAILED in 4m 20s +13 actionable tasks: 13 executed ``` From ce5fd3a0258a582449709b11d1cd8d00527823e3 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:54:50 -0400 Subject: [PATCH 19/73] feat(auto): receive Talk call lifecycle in Telecom --- .../auto/call/TalkTelecomInteropReceiver.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt new file mode 100644 index 00000000000..d8f2d778fd0 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt @@ -0,0 +1,45 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto.call + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.nextcloud.talk.call.TalkCallInterop + +/** Receives package-local Talk call lifecycle events and mirrors them into Core-Telecom. */ +class TalkTelecomInteropReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val manager = TalkTelecomManager.get(context) + val callKey = intent.getStringExtra(TalkCallInterop.EXTRA_CALL_KEY).orEmpty() + + when (intent.action) { + TalkCallInterop.ACTION_INCOMING_CALL -> { + manager.onIncomingCall( + callKey = callKey, + callExtras = intent.getBundleExtra(TalkCallInterop.EXTRA_CALL_EXTRAS) ?: Bundle(), + displayName = intent.getStringExtra(TalkCallInterop.EXTRA_DISPLAY_NAME).orEmpty(), + video = intent.getBooleanExtra(TalkCallInterop.EXTRA_VIDEO, false) + ) + } + + TalkCallInterop.ACTION_CALL_STARTED -> { + manager.onCallStarted( + callKey = callKey, + callExtras = intent.getBundleExtra(TalkCallInterop.EXTRA_CALL_EXTRAS) ?: Bundle(), + displayName = intent.getStringExtra(TalkCallInterop.EXTRA_DISPLAY_NAME).orEmpty(), + incoming = intent.getBooleanExtra(TalkCallInterop.EXTRA_INCOMING, false), + video = intent.getBooleanExtra(TalkCallInterop.EXTRA_VIDEO, false) + ) + } + + TalkCallInterop.ACTION_CALL_ACTIVE -> manager.onCallActive(callKey) + TalkCallInterop.ACTION_CALL_ENDED -> manager.onCallEnded(callKey) + } + } +} From 7fb2cd3a29a4d4999f548dd6fff68978181a9cef Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:55:03 -0400 Subject: [PATCH 20/73] feat(auto): register Telecom interop receiver --- app/src/gplay/AndroidManifest.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 1b736e49813..33b8472cfc4 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -47,6 +47,17 @@ + + + + + + + + + From bb1556bb4346470ba601254fb02e9bd1213dab57 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:56:46 -0400 Subject: [PATCH 21/73] ci(auto): wire and validate Talk call bridge --- .../android-auto-wire-call-bridge.yml | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 .github/workflows/android-auto-wire-call-bridge.yml diff --git a/.github/workflows/android-auto-wire-call-bridge.yml b/.github/workflows/android-auto-wire-call-bridge.yml new file mode 100644 index 00000000000..364c82a990a --- /dev/null +++ b/.github/workflows/android-auto-wire-call-bridge.yml @@ -0,0 +1,142 @@ +name: Android Auto - wire Talk call bridge + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-wire-call-bridge.yml + +permissions: + contents: write + +jobs: + wire: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Patch Talk call lifecycle into Telecom bridge + shell: bash + run: | + python3 - <<'PY' + from pathlib import Path + + def replace_once(text: str, old: str, new: str, label: str) -> str: + count = text.count(old) + if count != 1: + raise SystemExit(f"{label}: expected exactly one match, found {count}") + return text.replace(old, new, 1) + + # NotificationWorker: publish incoming calls to the flavor-neutral bridge. + path = Path('app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt') + text = path.read_text() + if 'import com.nextcloud.talk.call.TalkCallInterop' not in text: + text = replace_once( + text, + 'import com.nextcloud.talk.callnotification.CallNotificationActivity\n', + 'import com.nextcloud.talk.call.TalkCallInterop\n' + 'import com.nextcloud.talk.callnotification.CallNotificationActivity\n', + 'NotificationWorker import' + ) + marker = ''' val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n''' + replacement = ''' val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n\n TalkCallInterop.notifyIncomingCall(\n applicationContext,\n bundle,\n conversation.displayName,\n isVideoCall\n )\n\n val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n''' + if 'TalkCallInterop.notifyIncomingCall(' not in text: + text = replace_once(text, marker, replacement, 'NotificationWorker incoming call hook') + path.write_text(text) + + # CallActivity: register package-local Telecom controls and publish WebRTC lifecycle. + path = Path('app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt') + text = path.read_text() + + if 'import com.nextcloud.talk.call.TalkCallInterop' not in text: + text = replace_once( + text, + 'import com.nextcloud.talk.call.ReactionAnimator\n', + 'import com.nextcloud.talk.call.ReactionAnimator\n' + 'import com.nextcloud.talk.call.TalkCallInterop\n', + 'CallActivity TalkCallInterop import' + ) + if 'import com.nextcloud.talk.utils.registerBroadcastReceiver' not in text: + text = replace_once( + text, + 'import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n', + 'import com.nextcloud.talk.utils.registerBroadcastReceiver\n' + 'import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n', + 'CallActivity registerBroadcastReceiver import' + ) + + field_marker = ''' private var isIncomingCallFromNotification = false\n private val callControlHandler = Handler()\n''' + field_replacement = ''' private var isIncomingCallFromNotification = false\n private var telecomControlReceiverRegistered = false\n private var activeTelecomCallKey: String? = null\n private val telecomControlReceiver = object : BroadcastReceiver() {\n override fun onReceive(context: Context?, intent: Intent?) {\n val action = intent?.action ?: return\n val callKey = intent.getStringExtra(TalkCallInterop.EXTRA_CALL_KEY)\n if (callKey.isNullOrBlank() || callKey != activeTelecomCallKey) return\n\n when (action) {\n TalkCallInterop.ACTION_CONTROL_DISCONNECT -> hangup(shutDownView = true, endCallForAll = false)\n TalkCallInterop.ACTION_CONTROL_MUTE -> {\n val shouldMute = intent.getBooleanExtra(TalkCallInterop.EXTRA_MUTED, false)\n if (microphoneOn == shouldMute) {\n onMicrophoneClick()\n }\n }\n }\n }\n }\n private val callControlHandler = Handler()\n''' + if 'telecomControlReceiverRegistered' not in text: + text = replace_once(text, field_marker, field_replacement, 'CallActivity Telecom receiver fields') + + oncreate_marker = ''' processExtras(intent.extras!!)\n conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n''' + oncreate_replacement = ''' processExtras(intent.extras!!)\n conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n val telecomAccountId = conversationUser.id\n val telecomRoomToken = roomToken\n if (telecomAccountId != null && !telecomRoomToken.isNullOrBlank()) {\n activeTelecomCallKey = TalkCallInterop.callKey(telecomAccountId, telecomRoomToken)\n registerTelecomControlReceiver()\n TalkCallInterop.notifyCallStarted(\n context = this,\n accountId = telecomAccountId,\n roomToken = telecomRoomToken,\n displayName = conversationName.orEmpty(),\n incoming = isIncomingCallFromNotification,\n video = !isVoiceOnlyCall,\n callExtras = Bundle(extras)\n )\n }\n\n credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n''' + if 'TalkCallInterop.notifyCallStarted(' not in text: + text = replace_once(text, oncreate_marker, oncreate_replacement, 'CallActivity start hook') + + helper_marker = ''' private fun initCallRecordingViewModel(recordingState: Int) {\n''' + helper_replacement = ''' private fun registerTelecomControlReceiver() {\n if (telecomControlReceiverRegistered) return\n val filter = IntentFilter().apply {\n addAction(TalkCallInterop.ACTION_CONTROL_DISCONNECT)\n addAction(TalkCallInterop.ACTION_CONTROL_MUTE)\n }\n registerBroadcastReceiver(telecomControlReceiver, filter, ReceiverFlag.NotExported)\n telecomControlReceiverRegistered = true\n }\n\n private fun initCallRecordingViewModel(recordingState: Int) {\n''' + if 'private fun registerTelecomControlReceiver()' not in text: + text = replace_once(text, helper_marker, helper_replacement, 'CallActivity receiver registration helper') + + destroy_marker = ''' CallForegroundService.stop(applicationContext)\n powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n super.onDestroy()\n''' + destroy_replacement = ''' CallForegroundService.stop(applicationContext)\n powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n if (telecomControlReceiverRegistered) {\n unregisterReceiver(telecomControlReceiver)\n telecomControlReceiverRegistered = false\n }\n super.onDestroy()\n''' + if 'unregisterReceiver(telecomControlReceiver)' not in text: + text = replace_once(text, destroy_marker, destroy_replacement, 'CallActivity receiver cleanup') + + hangup_marker = ''' private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n Log.d(TAG, "hangup! shutDownView=$shutDownView")\n joinRoomInitiated = false\n''' + hangup_replacement = ''' private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n Log.d(TAG, "hangup! shutDownView=$shutDownView")\n if (shutDownView && ::conversationUser.isInitialized) {\n val accountId = conversationUser.id\n val token = roomToken\n if (accountId != null && !token.isNullOrBlank()) {\n TalkCallInterop.notifyCallEnded(this, accountId, token)\n }\n }\n joinRoomInitiated = false\n''' + if 'TalkCallInterop.notifyCallEnded(this, accountId, token)' not in text: + text = replace_once(text, hangup_marker, hangup_replacement, 'CallActivity end hook') + + state_marker = ''' if (currentCallStatus == null || currentCallStatus !== callState) {\n currentCallStatus = callState\n if (handler == null) {\n''' + state_replacement = ''' if (currentCallStatus == null || currentCallStatus !== callState) {\n currentCallStatus = callState\n if (\n ::conversationUser.isInitialized &&\n (callState === CallStatus.JOINED || callState === CallStatus.IN_CONVERSATION)\n ) {\n val accountId = conversationUser.id\n val token = roomToken\n if (accountId != null && !token.isNullOrBlank()) {\n TalkCallInterop.notifyCallActive(this, accountId, token)\n }\n }\n if (handler == null) {\n''' + if 'TalkCallInterop.notifyCallActive(this, accountId, token)' not in text: + text = replace_once(text, state_marker, state_replacement, 'CallActivity active hook') + + path.write_text(text) + PY + + - name: Commit call bridge wiring + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ + app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt + git commit -m "feat(auto): wire Talk call lifecycle to Telecom" + + - name: Compile gplay debug Kotlin + id: compile + shell: bash + run: | + set +e + ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-call-build.log 2>&1 + rc=$? + echo "rc=$rc" >> "$GITHUB_OUTPUT" + exit 0 + + - name: Record build result and push + shell: bash + run: | + set -euo pipefail + rc='${{ steps.compile.outputs.rc }}' + if [ "$rc" = "0" ]; then result="PASS"; else result="FAIL"; fi + { + echo "# Android Auto call bridge build" + echo + echo "Result: **$result**" + echo + echo '```text' + tail -n 240 /tmp/android-auto-call-build.log + echo '```' + } > ANDROID_AUTO_CALL_BUILD_STATUS.md + git add ANDROID_AUTO_CALL_BUILD_STATUS.md + git commit -m "ci(auto): record call bridge compile result" + git push origin HEAD:android-auto From 75fa07be39244c1e7dfd4fb02cb1fb88411ed88b Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 15:59:12 -0400 Subject: [PATCH 22/73] fix(auto): distinguish Telecom answer and active transitions --- .../talk/auto/call/TalkTelecomManager.kt | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index aa74ba40e34..d3c3f2771b6 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -80,7 +80,9 @@ class TalkTelecomManager private constructor(context: Context) { if (existing != null) { existing.activityStarted = true existing.callExtras = Bundle(callExtras) - existing.control?.let { control -> scope.launch { control.setActive() } } + existing.control?.let { control -> + scope.launch { activateStartedCall(existing, control) } + } return } @@ -95,7 +97,14 @@ class TalkTelecomManager private constructor(context: Context) { } fun onCallActive(callKey: String) { - calls[callKey]?.control?.let { control -> scope.launch { control.setActive() } } + val managed = calls[callKey] ?: return + managed.control?.let { control -> + scope.launch { + if (!managed.incoming) { + control.setActive() + } + } + } } fun onCallEnded(callKey: String) { @@ -109,6 +118,26 @@ class TalkTelecomManager private constructor(context: Context) { } } + private suspend fun activateStartedCall(managed: ManagedCall, control: CallControlScope) { + runCatching { + when { + managed.incoming && !managed.answeredByTelecom -> { + control.answer( + if (managed.video) { + CallAttributesCompat.CALL_TYPE_VIDEO_CALL + } else { + CallAttributesCompat.CALL_TYPE_AUDIO_CALL + } + ) + } + + !managed.incoming -> control.setActive() + } + }.onFailure { + Log.w(TAG, "Unable to activate Talk call in Telecom: ${managed.callKey}", it) + } + } + private fun addCallIfNeeded( callKey: String, callExtras: Bundle, @@ -154,6 +183,7 @@ class TalkTelecomManager private constructor(context: Context) { callsManager.addCall( callAttributes = attributes, onAnswer = { requestedCallType -> + managed.answeredByTelecom = true launchTalkCall( managed, voiceOnly = requestedCallType != CallAttributesCompat.CALL_TYPE_VIDEO_CALL @@ -161,10 +191,15 @@ class TalkTelecomManager private constructor(context: Context) { }, onDisconnect = { cancelIncomingNotification(managed) - TalkCallInterop.requestDisconnect(appContext, managed.callKey) + if (managed.activityStarted) { + TalkCallInterop.requestDisconnect(appContext, managed.callKey) + } else { + calls.remove(managed.callKey) + } }, onSetActive = { if (!managed.activityStarted) { + managed.answeredByTelecom = managed.incoming launchTalkCall(managed, voiceOnly = !managed.video) } }, @@ -172,7 +207,11 @@ class TalkTelecomManager private constructor(context: Context) { // We intentionally do not advertise hold. If Telecom must make // the call inactive (for example for a cellular call), ending // Talk is safer than leaving WebRTC media active in the car. - TalkCallInterop.requestDisconnect(appContext, managed.callKey) + if (managed.activityStarted) { + TalkCallInterop.requestDisconnect(appContext, managed.callKey) + } else { + calls.remove(managed.callKey) + } } ) { managed.control = this @@ -185,8 +224,8 @@ class TalkTelecomManager private constructor(context: Context) { } } - if (!managed.incoming || managed.activityStarted) { - scope.launch { setActive() } + if (managed.activityStarted) { + scope.launch { activateStartedCall(managed, this@addCall) } } } } catch (t: Throwable) { @@ -225,6 +264,7 @@ class TalkTelecomManager private constructor(context: Context) { val incoming: Boolean, val video: Boolean, @Volatile var activityStarted: Boolean, + @Volatile var answeredByTelecom: Boolean = false, @Volatile var control: CallControlScope? = null ) From 99bec0d5524502ac834e860b11b0e6c7698b7ee2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:00:00 +0000 Subject: [PATCH 23/73] ci(auto): record foundation compile result --- ANDROID_AUTO_BUILD_STATUS.md | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md index 9958af714ea..5730e285eb5 100644 --- a/ANDROID_AUTO_BUILD_STATUS.md +++ b/ANDROID_AUTO_BUILD_STATUS.md @@ -3,13 +3,44 @@ Result: **FAIL** ```text +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:25:42: 'fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate' is deprecated. Use 'val property = extra[name] as Type' instead. See the Gradle 9.6 upgrading guide. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:45:1: 'fun Project.android(configure: Action): Unit' is deprecated. Replaced by com.android.build.api.dsl.ApplicationExtension. +This class is not used for the public extensions in AGP when android.newDsl=true, which is the default in AGP 9.0, and will be removed in AGP 10.0. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:102:41: 'fun srcDir(srcDir: Any): Any' is deprecated. Use `directories` mutable set instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:161:9: 'var htmlOutput: File?' is deprecated. Use SingleArtifact.LINT_HTML_REPORT or SingleArtifact.AGGREGATED_LINT_HTML_REPORT to cconsume lint report artifacts. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:162:9: 'var htmlReport: Boolean' is deprecated. Lint reports are now always generated. Use SingleArtifact.LINT_HTML_REPORT or SingleArtifact.AGGREGATED_LINT_HTML_REPORT to consume lint report artifacts. + +> Task :app:preBuild UP-TO-DATE +> Task :app:preGplayDebugBuild UP-TO-DATE + +> Task :app:dataBindingMergeDependencyArtifactsGplayDebug +WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/368eb3df2522b17368912c34129ebf3c1f0f9519/app-1.7.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. + Example of androidX reference: 'androidx/car/app/media/IMediaPlaybackHost' + Example of support library reference: 'android/support/v4/media/session/MediaSessionCompat$Token' +WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/androidx.media3/media3-session/1.11.0/494cabd189f6ffa23a95603bdbf85c6a9d85a0e7/media3-session-1.11.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. + Example of androidX reference: 'androidx/media3/session/legacy/MediaBrowserServiceCompat$2' + Example of support library reference: 'android/support/v4/media/MediaBrowserCompat$MediaItem' + +> Task :app:generateGplayDebugResources +> Task :app:generateGplayDebugBuildConfig +> Task :app:packageGplayDebugResources +> Task :app:processGplayDebugNavigationResources +> Task :app:parseGplayDebugLocalResources +> Task :app:mergeGplayDebugResources +> Task :app:generateGplayDebugRFile +> Task :app:dataBindingGenBaseClassesGplayDebug +> Task :app:kspGplayDebugKotlin +> Task :app:kaptGenerateStubsGplayDebugKotlin + > Task :app:kaptGplayDebugKotlin warning: The following options were not recognized by any processor: '[room.schemaLocation, kapt.kotlin.generated]' -> Task :app:compileGplayDebugKotlin FAILED +> Task :app:compileGplayDebugKotlin e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:9:24 Unresolved reference 'ApplicationInfo'. e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:32:40 Unresolved reference 'ApplicationInfo'. +> Task :app:compileGplayDebugKotlin FAILED + [Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html FAILURE: Build failed with an exception. @@ -57,37 +88,6 @@ org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:com at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:328) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376) - at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:111) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:146) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:131) - at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:35) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:54) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:43) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:40) - at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$executeTasks$0(DefaultBuildLifecycleController.java:323) - at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) - at org.gradle.internal.model.StateTransitionController.lambda$tryTransition$0(StateTransitionController.java:235) - at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) - at org.gradle.internal.model.StateTransitionController.tryTransition(StateTransitionController.java:235) - at org.gradle.internal.build.DefaultBuildLifecycleController.executeTasks(DefaultBuildLifecycleController.java:314) - at org.gradle.internal.build.DefaultBuildWorkGraphController$DefaultBuildWorkGraph.runWork(DefaultBuildWorkGraphController.java:220) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) - at org.gradle.composite.internal.DefaultBuildController.doRun(DefaultBuildController.java:182) - at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.lambda$run$0(DefaultBuildController.java:199) - at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) - at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.run(DefaultBuildController.java:199) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork @@ -208,7 +208,7 @@ Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionExcept at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:38) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:68) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:132) - ... 61 more + ... 30 more Caused by: org.jetbrains.kotlin.gradle.tasks.CompilationErrorException: Compilation error. See log for more details at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.throwExceptionIfCompilationFailed(tasksUtils.kt:21) at org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork.execute(BuildToolsApiCompilationWork.kt:320) @@ -251,6 +251,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 4m 20s +BUILD FAILED in 4m 53s 13 actionable tasks: 13 executed ``` From 1b978a546a1a02595374b58fb729a1f10c1b9796 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:01:53 -0400 Subject: [PATCH 24/73] fix(auto): stabilize Telecom call control scope --- .../java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index d3c3f2771b6..3b8aff0afed 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -214,7 +214,8 @@ class TalkTelecomManager private constructor(context: Context) { } } ) { - managed.control = this + val callControl = this + managed.control = callControl scope.launch { isMuted @@ -225,7 +226,7 @@ class TalkTelecomManager private constructor(context: Context) { } if (managed.activityStarted) { - scope.launch { activateStartedCall(managed, this@addCall) } + scope.launch { activateStartedCall(managed, callControl) } } } } catch (t: Throwable) { From b9dcbd002681acbf30dff382f85676c00bd8ed6a Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:02:40 -0400 Subject: [PATCH 25/73] build(auto): add reusable call bridge patcher --- scripts/android-auto-wire-call-bridge.py | 212 +++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 scripts/android-auto-wire-call-bridge.py diff --git a/scripts/android-auto-wire-call-bridge.py b/scripts/android-auto-wire-call-bridge.py new file mode 100644 index 00000000000..5bb62312251 --- /dev/null +++ b/scripts/android-auto-wire-call-bridge.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 +"""Wire Talk's shared WebRTC call lifecycle into the optional Android Auto Telecom bridge.""" + +from pathlib import Path + + +def replace_once(text: str, old: str, new: str, label: str) -> str: + count = text.count(old) + if count != 1: + raise SystemExit(f"{label}: expected exactly one match, found {count}") + return text.replace(old, new, 1) + + +def patch_notification_worker() -> None: + path = Path("app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt") + text = path.read_text() + + if "import com.nextcloud.talk.call.TalkCallInterop" not in text: + text = replace_once( + text, + "import com.nextcloud.talk.callnotification.CallNotificationActivity\n", + "import com.nextcloud.talk.call.TalkCallInterop\n" + "import com.nextcloud.talk.callnotification.CallNotificationActivity\n", + "NotificationWorker TalkCallInterop import", + ) + + marker = ( + " val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n" + " val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n" + ) + replacement = ( + " val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n\n" + " TalkCallInterop.notifyIncomingCall(\n" + " applicationContext,\n" + " bundle,\n" + " conversation.displayName,\n" + " isVideoCall\n" + " )\n\n" + " val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n" + ) + if "TalkCallInterop.notifyIncomingCall(" not in text: + text = replace_once(text, marker, replacement, "NotificationWorker incoming call hook") + + path.write_text(text) + + +def patch_call_activity() -> None: + path = Path("app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt") + text = path.read_text() + + if "import com.nextcloud.talk.call.TalkCallInterop" not in text: + text = replace_once( + text, + "import com.nextcloud.talk.call.ReactionAnimator\n", + "import com.nextcloud.talk.call.ReactionAnimator\n" + "import com.nextcloud.talk.call.TalkCallInterop\n", + "CallActivity TalkCallInterop import", + ) + + if "import com.nextcloud.talk.utils.registerBroadcastReceiver" not in text: + text = replace_once( + text, + "import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n", + "import com.nextcloud.talk.utils.registerBroadcastReceiver\n" + "import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n", + "CallActivity registerBroadcastReceiver import", + ) + + field_marker = ( + " private var isIncomingCallFromNotification = false\n" + " private val callControlHandler = Handler()\n" + ) + field_replacement = ( + " private var isIncomingCallFromNotification = false\n" + " private var telecomControlReceiverRegistered = false\n" + " private var activeTelecomCallKey: String? = null\n" + " private val telecomControlReceiver = object : BroadcastReceiver() {\n" + " override fun onReceive(context: Context?, intent: Intent?) {\n" + " val action = intent?.action ?: return\n" + " val callKey = intent.getStringExtra(TalkCallInterop.EXTRA_CALL_KEY)\n" + " if (callKey.isNullOrBlank() || callKey != activeTelecomCallKey) return\n\n" + " when (action) {\n" + " TalkCallInterop.ACTION_CONTROL_DISCONNECT ->\n" + " hangup(shutDownView = true, endCallForAll = false)\n\n" + " TalkCallInterop.ACTION_CONTROL_MUTE -> {\n" + " val shouldMute = intent.getBooleanExtra(TalkCallInterop.EXTRA_MUTED, false)\n" + " if (microphoneOn == shouldMute) {\n" + " onMicrophoneClick()\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " private val callControlHandler = Handler()\n" + ) + if "telecomControlReceiverRegistered" not in text: + text = replace_once(text, field_marker, field_replacement, "CallActivity Telecom receiver fields") + + oncreate_marker = ( + " processExtras(intent.extras!!)\n" + " conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n" + " credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n" + ) + oncreate_replacement = ( + " processExtras(intent.extras!!)\n" + " conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n" + " val telecomAccountId = conversationUser.id\n" + " val telecomRoomToken = roomToken\n" + " if (telecomAccountId != null && !telecomRoomToken.isNullOrBlank()) {\n" + " activeTelecomCallKey = TalkCallInterop.callKey(telecomAccountId, telecomRoomToken)\n" + " registerTelecomControlReceiver()\n" + " TalkCallInterop.notifyCallStarted(\n" + " context = this,\n" + " accountId = telecomAccountId,\n" + " roomToken = telecomRoomToken,\n" + " displayName = conversationName.orEmpty(),\n" + " incoming = isIncomingCallFromNotification,\n" + " video = !isVoiceOnlyCall,\n" + " callExtras = Bundle(extras)\n" + " )\n" + " }\n\n" + " credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n" + ) + if "TalkCallInterop.notifyCallStarted(" not in text: + text = replace_once(text, oncreate_marker, oncreate_replacement, "CallActivity call-start hook") + + helper_marker = " private fun initCallRecordingViewModel(recordingState: Int) {\n" + helper_replacement = ( + " private fun registerTelecomControlReceiver() {\n" + " if (telecomControlReceiverRegistered) return\n" + " val filter = IntentFilter().apply {\n" + " addAction(TalkCallInterop.ACTION_CONTROL_DISCONNECT)\n" + " addAction(TalkCallInterop.ACTION_CONTROL_MUTE)\n" + " }\n" + " registerBroadcastReceiver(telecomControlReceiver, filter, ReceiverFlag.NotExported)\n" + " telecomControlReceiverRegistered = true\n" + " }\n\n" + " private fun initCallRecordingViewModel(recordingState: Int) {\n" + ) + if "private fun registerTelecomControlReceiver()" not in text: + text = replace_once(text, helper_marker, helper_replacement, "CallActivity Telecom receiver helper") + + destroy_marker = ( + " CallForegroundService.stop(applicationContext)\n" + " powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n" + " super.onDestroy()\n" + ) + destroy_replacement = ( + " CallForegroundService.stop(applicationContext)\n" + " powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n" + " if (telecomControlReceiverRegistered) {\n" + " unregisterReceiver(telecomControlReceiver)\n" + " telecomControlReceiverRegistered = false\n" + " }\n" + " super.onDestroy()\n" + ) + if "unregisterReceiver(telecomControlReceiver)" not in text: + text = replace_once(text, destroy_marker, destroy_replacement, "CallActivity receiver cleanup") + + hangup_marker = ( + " private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n" + " Log.d(TAG, \"hangup! shutDownView=$shutDownView\")\n" + " joinRoomInitiated = false\n" + ) + hangup_replacement = ( + " private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n" + " Log.d(TAG, \"hangup! shutDownView=$shutDownView\")\n" + " if (shutDownView && ::conversationUser.isInitialized) {\n" + " val accountId = conversationUser.id\n" + " val token = roomToken\n" + " if (accountId != null && !token.isNullOrBlank()) {\n" + " TalkCallInterop.notifyCallEnded(this, accountId, token)\n" + " }\n" + " }\n" + " joinRoomInitiated = false\n" + ) + if "TalkCallInterop.notifyCallEnded(this, accountId, token)" not in text: + text = replace_once(text, hangup_marker, hangup_replacement, "CallActivity call-end hook") + + state_marker = ( + " if (currentCallStatus == null || currentCallStatus !== callState) {\n" + " currentCallStatus = callState\n" + " if (handler == null) {\n" + ) + state_replacement = ( + " if (currentCallStatus == null || currentCallStatus !== callState) {\n" + " currentCallStatus = callState\n" + " if (\n" + " ::conversationUser.isInitialized &&\n" + " (callState === CallStatus.JOINED || callState === CallStatus.IN_CONVERSATION)\n" + " ) {\n" + " val accountId = conversationUser.id\n" + " val token = roomToken\n" + " if (accountId != null && !token.isNullOrBlank()) {\n" + " TalkCallInterop.notifyCallActive(this, accountId, token)\n" + " }\n" + " }\n" + " if (handler == null) {\n" + ) + if "TalkCallInterop.notifyCallActive(this, accountId, token)" not in text: + text = replace_once(text, state_marker, state_replacement, "CallActivity call-active hook") + + path.write_text(text) + + +def main() -> None: + patch_notification_worker() + patch_call_activity() + + +if __name__ == "__main__": + main() From b995f2bb1781014a8e0abe3f7e05f16bec3f2b91 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:02:51 -0400 Subject: [PATCH 26/73] ci(auto): apply and compile call bridge safely --- .../android-auto-apply-call-bridge.yml | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 .github/workflows/android-auto-apply-call-bridge.yml diff --git a/.github/workflows/android-auto-apply-call-bridge.yml b/.github/workflows/android-auto-apply-call-bridge.yml new file mode 100644 index 00000000000..e73e1126646 --- /dev/null +++ b/.github/workflows/android-auto-apply-call-bridge.yml @@ -0,0 +1,71 @@ +name: Android Auto - apply call bridge + +on: + push: + branches: + - android-auto + paths: + - .github/workflows/android-auto-apply-call-bridge.yml + +permissions: + contents: write + +jobs: + apply-and-build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto + fetch-depth: 0 + + - name: Apply shared Talk call bridge patches + run: python3 scripts/android-auto-wire-call-bridge.py + + - name: Commit source wiring + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ + app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt + if ! git diff --cached --quiet; then + git commit -m "feat(auto): wire Talk call lifecycle to Telecom" + fi + git fetch origin android-auto + git rebase origin/android-auto + + - name: Compile gplay debug Kotlin + id: compile + run: | + set +e + ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-call-build.log 2>&1 + rc=$? + echo "rc=$rc" >> "$GITHUB_OUTPUT" + exit 0 + + - name: Record compiler result + run: | + set -euo pipefail + rc='${{ steps.compile.outputs.rc }}' + if [ "$rc" = "0" ]; then result="PASS"; else result="FAIL"; fi + { + echo "# Android Auto call bridge build" + echo + echo "Result: **$result**" + echo + echo '```text' + tail -n 240 /tmp/android-auto-call-build.log + echo '```' + } > ANDROID_AUTO_CALL_BUILD_STATUS.md + git add ANDROID_AUTO_CALL_BUILD_STATUS.md + if ! git diff --cached --quiet; then + git commit -m "ci(auto): record call bridge compile result" + fi + + - name: Rebase and push results + run: | + set -euo pipefail + git fetch origin android-auto + git rebase origin/android-auto + git push origin HEAD:android-auto From 15f4f26522bf74ac16e09eeafdb984bb522c7488 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:04:06 -0400 Subject: [PATCH 27/73] build(auto): add Android Auto dependency updater --- scripts/android-auto-update-dependencies.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 scripts/android-auto-update-dependencies.py diff --git a/scripts/android-auto-update-dependencies.py b/scripts/android-auto-update-dependencies.py new file mode 100644 index 00000000000..d7923f3e582 --- /dev/null +++ b/scripts/android-auto-update-dependencies.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +"""Keep Android Auto-specific dependencies on the selected current versions.""" + +from pathlib import Path + +path = Path("app/build.gradle.kts") +text = path.read_text() +old = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-alpha06")' +new = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-beta01")' + +if new not in text: + count = text.count(old) + if count != 1: + raise SystemExit(f"core-telecom dependency: expected one alpha06 line, found {count}") + text = text.replace(old, new, 1) + +path.write_text(text) From d4a30c86b2719b29085bb1ee26dd7be39499e761 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:04:36 -0400 Subject: [PATCH 28/73] ci(auto): compile call bridge against Core-Telecom beta --- .../workflows/android-auto-apply-call-bridge.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/android-auto-apply-call-bridge.yml b/.github/workflows/android-auto-apply-call-bridge.yml index e73e1126646..be29ffb3ac6 100644 --- a/.github/workflows/android-auto-apply-call-bridge.yml +++ b/.github/workflows/android-auto-apply-call-bridge.yml @@ -19,18 +19,21 @@ jobs: ref: android-auto fetch-depth: 0 - - name: Apply shared Talk call bridge patches - run: python3 scripts/android-auto-wire-call-bridge.py + - name: Apply Android Auto source and dependency patches + run: | + python3 scripts/android-auto-wire-call-bridge.py + python3 scripts/android-auto-update-dependencies.py - - name: Commit source wiring + - name: Commit wiring and dependency update run: | set -euo pipefail git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ + git add app/build.gradle.kts \ + app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt if ! git diff --cached --quiet; then - git commit -m "feat(auto): wire Talk call lifecycle to Telecom" + git commit -m "feat(auto): wire Talk calls to current Core-Telecom" fi git fetch origin android-auto git rebase origin/android-auto From 4cb850796d441a804086b882f30e36d308ff64f3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:04:49 +0000 Subject: [PATCH 29/73] feat(auto): wire Talk calls to current Core-Telecom --- app/build.gradle.kts | 2 +- .../nextcloud/talk/activities/CallActivity.kt | 70 +++++++++++++++++++ .../nextcloud/talk/jobs/NotificationWorker.kt | 9 +++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a861ffc8588..05d3a4b4be5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -197,7 +197,7 @@ 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") + "gplayImplementation"("androidx.core:core-telecom:1.1.0-beta01") implementation("androidx.media3:media3-session:1.11.0") kapt("org.jetbrains.kotlin:kotlin-metadata-jvm:$kotlinVersion") implementation("androidx.room:room-testing-android:$roomVersion") diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt index a27a42c0b77..caaa57f0af9 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -72,6 +72,7 @@ import com.nextcloud.talk.call.MessageSenderMcu import com.nextcloud.talk.call.MessageSenderNoMcu import com.nextcloud.talk.call.MutableLocalCallParticipantModel import com.nextcloud.talk.call.ReactionAnimator +import com.nextcloud.talk.call.TalkCallInterop import com.nextcloud.talk.call.components.ParticipantGrid import com.nextcloud.talk.call.components.SelfVideoView import com.nextcloud.talk.call.components.screenshare.ScreenShareComponent @@ -141,6 +142,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_START_CALL_AFTER_ROOM_SWIT import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SWITCH_TO_ROOM import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.power.PowerManagerUtils +import com.nextcloud.talk.utils.registerBroadcastReceiver import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver import com.nextcloud.talk.utils.singletons.ApplicationWideCurrentRoomHolder import com.nextcloud.talk.viewmodels.CallRecordingViewModel @@ -253,6 +255,27 @@ class CallActivity : CallBaseActivity() { var isVoiceOnlyCall = false private var isCallWithoutNotification = false private var isIncomingCallFromNotification = false + private var telecomControlReceiverRegistered = false + private var activeTelecomCallKey: String? = null + private val telecomControlReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + val action = intent?.action ?: return + val callKey = intent.getStringExtra(TalkCallInterop.EXTRA_CALL_KEY) + if (callKey.isNullOrBlank() || callKey != activeTelecomCallKey) return + + when (action) { + TalkCallInterop.ACTION_CONTROL_DISCONNECT -> + hangup(shutDownView = true, endCallForAll = false) + + TalkCallInterop.ACTION_CONTROL_MUTE -> { + val shouldMute = intent.getBooleanExtra(TalkCallInterop.EXTRA_MUTED, false) + if (microphoneOn == shouldMute) { + onMicrophoneClick() + } + } + } + } + } private val callControlHandler = Handler() private val callInfosHandler = Handler() private val cameraSwitchHandler = Handler() @@ -453,6 +476,22 @@ class CallActivity : CallBaseActivity() { processExtras(intent.extras!!) conversationUser = currentUserProviderOld.currentUser.blockingGet() + val telecomAccountId = conversationUser.id + val telecomRoomToken = roomToken + if (telecomAccountId != null && !telecomRoomToken.isNullOrBlank()) { + activeTelecomCallKey = TalkCallInterop.callKey(telecomAccountId, telecomRoomToken) + registerTelecomControlReceiver() + TalkCallInterop.notifyCallStarted( + context = this, + accountId = telecomAccountId, + roomToken = telecomRoomToken, + displayName = conversationName.orEmpty(), + incoming = isIncomingCallFromNotification, + video = !isVoiceOnlyCall, + callExtras = Bundle(extras) + ) + } + credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) if (TextUtils.isEmpty(baseUrl)) { baseUrl = conversationUser!!.baseUrl @@ -475,6 +514,16 @@ class CallActivity : CallBaseActivity() { checkInitialDevicePermissions() } + private fun registerTelecomControlReceiver() { + if (telecomControlReceiverRegistered) return + val filter = IntentFilter().apply { + addAction(TalkCallInterop.ACTION_CONTROL_DISCONNECT) + addAction(TalkCallInterop.ACTION_CONTROL_MUTE) + } + registerBroadcastReceiver(telecomControlReceiver, filter, ReceiverFlag.NotExported) + telecomControlReceiverRegistered = true + } + private fun initCallRecordingViewModel(recordingState: Int) { callRecordingViewModel = ViewModelProvider(this, viewModelFactory).get( CallRecordingViewModel::class.java @@ -1391,6 +1440,10 @@ class CallActivity : CallBaseActivity() { } CallForegroundService.stop(applicationContext) powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE) + if (telecomControlReceiverRegistered) { + unregisterReceiver(telecomControlReceiver) + telecomControlReceiverRegistered = false + } super.onDestroy() } @@ -1966,6 +2019,13 @@ class CallActivity : CallBaseActivity() { private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) { Log.d(TAG, "hangup! shutDownView=$shutDownView") + if (shutDownView && ::conversationUser.isInitialized) { + val accountId = conversationUser.id + val token = roomToken + if (accountId != null && !token.isNullOrBlank()) { + TalkCallInterop.notifyCallEnded(this, accountId, token) + } + } joinRoomInitiated = false if (shutDownView) { setCallState(CallStatus.LEAVING) @@ -2639,6 +2699,16 @@ class CallActivity : CallBaseActivity() { private fun setCallState(callState: CallStatus) { if (currentCallStatus == null || currentCallStatus !== callState) { currentCallStatus = callState + if ( + ::conversationUser.isInitialized && + (callState === CallStatus.JOINED || callState === CallStatus.IN_CONVERSATION) + ) { + val accountId = conversationUser.id + val token = roomToken + if (accountId != null && !token.isNullOrBlank()) { + TalkCallInterop.notifyCallActive(this, accountId, token) + } + } if (handler == null) { handler = Handler(Looper.getMainLooper()) } else { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt index d75ccbc5935..b66fb16bed7 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -55,6 +55,7 @@ import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager +import com.nextcloud.talk.call.TalkCallInterop import com.nextcloud.talk.callnotification.CallNotificationActivity import com.nextcloud.talk.chat.data.network.ChatNetworkDataSource import com.nextcloud.talk.conversationlist.DirectShareHelper @@ -358,6 +359,14 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val callerPerson = callerPersonBuilder.build() val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0 + + TalkCallInterop.notifyIncomingCall( + applicationContext, + bundle, + conversation.displayName, + isVideoCall + ) + val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent val notification = From e263c1763598b71d998d8dec4d417914a4f42714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:06:39 +0000 Subject: [PATCH 30/73] ci(auto): record call bridge compile result --- ANDROID_AUTO_CALL_BUILD_STATUS.md | 246 ++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 ANDROID_AUTO_CALL_BUILD_STATUS.md diff --git a/ANDROID_AUTO_CALL_BUILD_STATUS.md b/ANDROID_AUTO_CALL_BUILD_STATUS.md new file mode 100644 index 00000000000..8e2dab5fec5 --- /dev/null +++ b/ANDROID_AUTO_CALL_BUILD_STATUS.md @@ -0,0 +1,246 @@ +# Android Auto call bridge build + +Result: **FAIL** + +```text + at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2$1.accept(WorkNodeCodec.kt:399) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2$1.accept(WorkNodeCodec.kt:398) + at org.gradle.api.internal.project.DefaultProjectState.lambda$applyToMutableState$0(DefaultProjectState.java:241) + at org.gradle.api.internal.project.DefaultProjectState.lambda$fromMutableState$0(DefaultProjectState.java:248) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withReplacedLocks$0(DefaultWorkerLeaseService.java:452) + at org.gradle.internal.work.DefaultWorkerLeaseService.withoutLocks(DefaultWorkerLeaseService.java:374) + at org.gradle.internal.work.DefaultWorkerLeaseService.withReplacedLocks(DefaultWorkerLeaseService.java:451) + at org.gradle.api.internal.project.DefaultProjectState.runWithModelLock(DefaultProjectState.java:276) + at org.gradle.api.internal.project.DefaultProjectState.fromMutableState(DefaultProjectState.java:248) + at org.gradle.api.internal.project.DefaultProjectState.applyToMutableState(DefaultProjectState.java:240) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invokeSuspend(WorkNodeCodec.kt:398) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invoke(WorkNodeCodec.kt) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invoke(WorkNodeCodec.kt) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invokeSuspend(WorkNodeCodec.kt:331) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invoke(WorkNodeCodec.kt) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invoke(WorkNodeCodec.kt) + at org.gradle.internal.serialize.graph.RunningKt$runWriteOperation$1.invokeSuspend(Running.kt:43) + at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34) + at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115) + at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) + at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeGroupedNodes(WorkNodeCodec.kt:327) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodeBatchesInParallel$lambda$1$0$0(WorkNodeCodec.kt:248) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$runBuildOperations$1$1.execute$lambda$1(WorkNodeCodec.kt:597) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodecKt$asBuildOperation$1.run(WorkNodeCodec.kt:640) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$executeInParallel$0(DefaultBuildOperationExecutor.java:106) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:416) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.doRunBatch(DefaultBuildOperationQueue.java:407) + at org.gradle.internal.operations.DefaultBuildOperationQueue.withProjectLockChangePolicy(DefaultBuildOperationQueue.java:209) + at org.gradle.internal.operations.DefaultBuildOperationQueue.access$900(DefaultBuildOperationQueue.java:38) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.executePendingWork(DefaultBuildOperationQueue.java:378) + at org.gradle.internal.work.DefaultWorkerLeaseService.tryRunAsWorkerThread(DefaultWorkerLeaseService.java:145) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatchWithLeaseRetry$0(DefaultBuildOperationQueue.java:353) + at org.gradle.internal.time.ExponentialBackoff.retryUntil(ExponentialBackoff.java:69) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatchWithLeaseRetry(DefaultBuildOperationQueue.java:352) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:338) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runOperations$0(DefaultBuildOperationQueue.java:269) + at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperations(DefaultBuildOperationQueue.java:266) + at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$000(DefaultBuildOperationQueue.java:245) + at org.gradle.internal.operations.DefaultBuildOperationQueue.waitForCompletion(DefaultBuildOperationQueue.java:146) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.executeInParallel(DefaultBuildOperationExecutor.java:119) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAllWithAccessToProjectState(DefaultBuildOperationExecutor.java:83) + at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAllWithAccessToProjectState(DefaultBuildOperationExecutor.java:78) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.runBuildOperations$lambda$0(WorkNodeCodec.kt:588) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.handleBuildOperationExceptions(WorkNodeCodec.kt:286) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.runBuildOperations(WorkNodeCodec.kt:587) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodeBatchesInParallel(WorkNodeCodec.kt:243) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodes(WorkNodeCodec.kt:209) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.doWrite(WorkNodeCodec.kt:122) + at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeWork(WorkNodeCodec.kt:94) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeWorkGraphOf(ConfigurationCacheState.kt:570) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildContent$org_gradle_configuration_cache(ConfigurationCacheState.kt:524) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildState(ConfigurationCacheState.kt:363) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildsInTree(ConfigurationCacheState.kt:314) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeRootBuild(ConfigurationCacheState.kt:287) + at org.gradle.internal.cc.impl.ConfigurationCacheState.writeRootBuildState(ConfigurationCacheState.kt:185) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invokeSuspend(DefaultConfigurationCacheIO.kt:220) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invoke(DefaultConfigurationCacheIO.kt) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invoke(DefaultConfigurationCacheIO.kt) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invokeSuspend(DefaultConfigurationCacheIO.kt:369) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invoke(DefaultConfigurationCacheIO.kt) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invoke(DefaultConfigurationCacheIO.kt) + at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invokeSuspend(Codec.kt:84) + at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invoke(Codec.kt) + at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invoke(Codec.kt) + at org.gradle.internal.serialize.graph.RunningKt$runWriteOperation$1.invokeSuspend(Running.kt:43) + at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34) + at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115) + at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) + at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) + at org.gradle.internal.serialize.graph.CodecKt.writeWith(Codec.kt:83) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:521) + at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor(ConfigurationCacheBuildTreeIO.kt:131) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:101) + at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor$default(ConfigurationCacheBuildTreeIO.kt:124) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheStateWithSpecialEncoders(DefaultConfigurationCacheIO.kt:368) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0$0(DefaultConfigurationCacheIO.kt:272) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withSharedObjectEncoderFor(DefaultConfigurationCacheIO.kt:331) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0(DefaultConfigurationCacheIO.kt:271) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withStringEncoderFor(DefaultConfigurationCacheIO.kt:319) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState(DefaultConfigurationCacheIO.kt:270) + at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeRootBuildStateTo(DefaultConfigurationCacheIO.kt:218) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.writeConfigurationCacheState(DefaultConfigurationCache.kt:803) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0$0(DefaultConfigurationCache.kt:717) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore$lambda$0(DefaultConfigurationCache.kt:732) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore$lambda$0(ConfigurationCacheRepository.kt:255) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$withExclusiveAccessToCache$1.get(ConfigurationCacheRepository.kt:321) + at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) + at org.gradle.cache.internal.DefaultCacheCoordinator.withFileLock(DefaultCacheCoordinator.java:226) + at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:148) + at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingPersistentCache.withFileLock(DefaultCacheFactory.java:245) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository.withExclusiveAccessToCache(ConfigurationCacheRepository.kt:319) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository.access$withExclusiveAccessToCache(ConfigurationCacheRepository.kt:54) + at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore(ConfigurationCacheRepository.kt:245) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore(DefaultConfigurationCache.kt:729) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0(DefaultConfigurationCache.kt:716) + at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt$withWorkGraphStoreOperation$1.run(ConfigurationCacheBuildOperations.kt:63) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) + at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) + at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt.withWorkGraphStoreOperation(ConfigurationCacheBuildOperations.kt:56) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph(DefaultConfigurationCache.kt:715) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1$0(DefaultConfigurationCache.kt:282) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.degradeGracefullyOr(DefaultConfigurationCache.kt:342) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1(DefaultConfigurationCache.kt:282) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.runWorkThatContributesToCacheEntry(DefaultConfigurationCache.kt:654) + at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks(DefaultConfigurationCache.kt:279) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:57) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:56) + at org.gradle.internal.Try.ofFailable(Try.java:46) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:56) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:55) + at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:115) + at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:55) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$0(DefaultBuildTreeLifecycleController.java:80) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$0(DefaultBuildTreeLifecycleController.java:166) + at org.gradle.internal.model.StateTransitionController.lambda$transition$2(StateTransitionController.java:227) + at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) + at org.gradle.internal.model.StateTransitionController.lambda$transition$1(StateTransitionController.java:227) + at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) + at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:227) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:163) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:80) + at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:75) + at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31) + at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) + at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:55) + at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:83) + at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:118) + at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:64) + at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:97) + at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:119) + at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:97) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeLifecycle(DefaultBuildTreeActionExecutor.java:126) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.access$100(DefaultBuildTreeActionExecutor.java:52) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:98) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:94) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) + at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) + at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runAsBuildOperation(DefaultBuildTreeActionExecutor.java:94) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.lambda$runBuildTreeAction$0(DefaultBuildTreeActionExecutor.java:88) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) + at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeAction(DefaultBuildTreeActionExecutor.java:88) + at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:111) + at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64) + at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:106) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:94) + at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:73) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:67) + at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:45) + at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:57) + at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:32) + at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:51) + at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:39) + at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:47) + at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:31) + at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:70) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:40) + at org.gradle.internal.daemon.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:80) + at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables.doBuild(ApplyClientEnvironmentVariables.java:80) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:74) + at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) + at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) + at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) + at org.gradle.launcher.daemon.server.DaemonStateCoordinator.lambda$runCommand$0(DaemonStateCoordinator.java:321) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) +Caused by: org.gradle.api.internal.artifacts.ivyservice.TypedResolveException: Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. + at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailure(ResolveExceptionMapper.java:73) + at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailures(ResolveExceptionMapper.java:65) + at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$DefaultResolutionHost.consolidateFailures(DefaultConfiguration.java:1801) + at org.gradle.api.internal.artifacts.configurations.ResolutionHost.rethrowFailuresAndReportProblems(ResolutionHost.java:75) + at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.maybeThrowResolutionFailures(ResolutionBackedFileCollection.java:86) + at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:76) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) + at org.gradle.internal.serialize.codecs.core.CollectingVisitor.startVisit(FileCollectionCodec.kt:208) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:357) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeViaCollectingVisitor(FileCollectionCodec.kt:81) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeContents(FileCollectionCodec.kt:74) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:63) + at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:55) + at org.gradle.internal.serialize.graph.codecs.BindingsBackedCodec.encode(BindingsBackedCodec.kt:66) + at org.gradle.internal.serialize.graph.DefaultWriteContext.write(Contexts.kt:111) + at org.gradle.internal.serialize.graph.BeanPropertyExtensionsKt.writePropertyValue(BeanPropertyExtensions.kt:34) + ... 230 more +Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find androidx.core:core-telecom:1.1.0-beta01. +Required by: + project ':app' + + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. + +BUILD FAILED in 1m 47s +Configuration cache entry discarded due to serialization error. +``` From 9be77ef25384457404797095166944c93962c793 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:07:07 -0400 Subject: [PATCH 31/73] ci(auto): expose call bridge build as PR check --- .github/workflows/android-auto-apply-call-bridge.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/android-auto-apply-call-bridge.yml b/.github/workflows/android-auto-apply-call-bridge.yml index be29ffb3ac6..025631a4917 100644 --- a/.github/workflows/android-auto-apply-call-bridge.yml +++ b/.github/workflows/android-auto-apply-call-bridge.yml @@ -6,6 +6,11 @@ on: - android-auto paths: - .github/workflows/android-auto-apply-call-bridge.yml + pull_request: + branches: + - master + paths: + - .github/workflows/android-auto-apply-call-bridge.yml permissions: contents: write From 7881211ea14ce51650b72a6405ac5b5d83c93a10 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:08:14 +0000 Subject: [PATCH 32/73] ci(auto): record foundation compile result --- ANDROID_AUTO_BUILD_STATUS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md index 5730e285eb5..bbc3b8c2b0d 100644 --- a/ANDROID_AUTO_BUILD_STATUS.md +++ b/ANDROID_AUTO_BUILD_STATUS.md @@ -3,6 +3,9 @@ Result: **FAIL** ```text +The current default is 'false'. +It will be removed in version 10.0 of the Android Gradle plugin. +Add android.sync.suppressAgpWarnings=UNSUPPORTED_PROJECT_OPTION_USE to the gradle.properties file to suppress this warning. w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:25:42: 'fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate' is deprecated. Use 'val property = extra[name] as Type' instead. See the Gradle 9.6 upgrading guide. w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:45:1: 'fun Project.android(configure: Action): Unit' is deprecated. Replaced by com.android.build.api.dsl.ApplicationExtension. This class is not used for the public extensions in AGP when android.newDsl=true, which is the default in AGP 9.0, and will be removed in AGP 10.0. @@ -12,7 +15,6 @@ w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_A > Task :app:preBuild UP-TO-DATE > Task :app:preGplayDebugBuild UP-TO-DATE - > Task :app:dataBindingMergeDependencyArtifactsGplayDebug WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/368eb3df2522b17368912c34129ebf3c1f0f9519/app-1.7.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. Example of androidX reference: 'androidx/car/app/media/IMediaPlaybackHost' @@ -35,12 +37,10 @@ WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/an > Task :app:kaptGplayDebugKotlin warning: The following options were not recognized by any processor: '[room.schemaLocation, kapt.kotlin.generated]' -> Task :app:compileGplayDebugKotlin +> Task :app:compileGplayDebugKotlin FAILED e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:9:24 Unresolved reference 'ApplicationInfo'. e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:32:40 Unresolved reference 'ApplicationInfo'. -> Task :app:compileGplayDebugKotlin FAILED - [Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html FAILURE: Build failed with an exception. @@ -251,6 +251,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 4m 53s +BUILD FAILED in 6m 13 actionable tasks: 13 executed ``` From e990dfe0ba1be5da98912d4af4d6730ae445ab9c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:09:00 +0000 Subject: [PATCH 33/73] ci(auto): record call bridge compile result --- ANDROID_AUTO_CALL_BUILD_STATUS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ANDROID_AUTO_CALL_BUILD_STATUS.md b/ANDROID_AUTO_CALL_BUILD_STATUS.md index 8e2dab5fec5..6db8e228c54 100644 --- a/ANDROID_AUTO_CALL_BUILD_STATUS.md +++ b/ANDROID_AUTO_CALL_BUILD_STATUS.md @@ -241,6 +241,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 1m 47s +BUILD FAILED in 1m 37s Configuration cache entry discarded due to serialization error. ``` From 21f533d0404c9b1fdf6cac3dfb88aae03e7f820d Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:10:32 -0400 Subject: [PATCH 34/73] fix(auto): import ApplicationInfo from pm --- app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt index b7eb0e2b772..329e8046b20 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt @@ -6,8 +6,8 @@ */ package com.nextcloud.talk.auto -import android.content.ApplicationInfo import android.content.Intent +import android.content.pm.ApplicationInfo import androidx.car.app.CarAppService import androidx.car.app.CarContext import androidx.car.app.Screen From ca87d585cfc571d8cd2b986fea604646d8647c01 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:10:49 -0400 Subject: [PATCH 35/73] fix(auto): keep latest published Core-Telecom artifact --- scripts/android-auto-update-dependencies.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/android-auto-update-dependencies.py b/scripts/android-auto-update-dependencies.py index d7923f3e582..14bb8504bc5 100644 --- a/scripts/android-auto-update-dependencies.py +++ b/scripts/android-auto-update-dependencies.py @@ -1,17 +1,17 @@ #!/usr/bin/env python3 -"""Keep Android Auto-specific dependencies on the selected current versions.""" +"""Keep Android Auto-specific dependencies on the latest published versions.""" from pathlib import Path path = Path("app/build.gradle.kts") text = path.read_text() -old = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-alpha06")' -new = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-beta01")' +target = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-alpha06")' +unpublished = '"gplayImplementation"("androidx.core:core-telecom:1.1.0-beta01")' -if new not in text: - count = text.count(old) +if target not in text: + count = text.count(unpublished) if count != 1: - raise SystemExit(f"core-telecom dependency: expected one alpha06 line, found {count}") - text = text.replace(old, new, 1) + raise SystemExit(f"core-telecom dependency: expected one beta01 line to restore, found {count}") + text = text.replace(unpublished, target, 1) path.write_text(text) From f26a76415b354afb37b9ae0707962ae26d9d609e Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:11:32 -0400 Subject: [PATCH 36/73] ci(auto): rerun call bridge on published Telecom --- .github/workflows/android-auto-apply-call-bridge.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/android-auto-apply-call-bridge.yml b/.github/workflows/android-auto-apply-call-bridge.yml index 025631a4917..35722d8d186 100644 --- a/.github/workflows/android-auto-apply-call-bridge.yml +++ b/.github/workflows/android-auto-apply-call-bridge.yml @@ -24,7 +24,7 @@ jobs: ref: android-auto fetch-depth: 0 - - name: Apply Android Auto source and dependency patches + - name: Apply Android Auto source and published dependency patches run: | python3 scripts/android-auto-wire-call-bridge.py python3 scripts/android-auto-update-dependencies.py @@ -38,7 +38,7 @@ jobs: app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt if ! git diff --cached --quiet; then - git commit -m "feat(auto): wire Talk calls to current Core-Telecom" + git commit -m "feat(auto): wire Talk calls to published Core-Telecom" fi git fetch origin android-auto git rebase origin/android-auto From 5d44b2fea001f83315c228bc039743fec44b528e Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:12:12 -0400 Subject: [PATCH 37/73] fix(auto): import Flow collect for Telecom mute bridge --- .../java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index 3b8aff0afed..2647ee8242b 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -24,6 +24,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch import java.util.concurrent.ConcurrentHashMap From 5b02a4305d857fcdb41968464be33665df40b739 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:12:18 +0000 Subject: [PATCH 38/73] ci(auto): record call bridge compile result --- ANDROID_AUTO_CALL_BUILD_STATUS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ANDROID_AUTO_CALL_BUILD_STATUS.md b/ANDROID_AUTO_CALL_BUILD_STATUS.md index 6db8e228c54..3a803ad7b25 100644 --- a/ANDROID_AUTO_CALL_BUILD_STATUS.md +++ b/ANDROID_AUTO_CALL_BUILD_STATUS.md @@ -241,6 +241,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 1m 37s +BUILD FAILED in 1m 26s Configuration cache entry discarded due to serialization error. ``` From a12f05ae80a09065d394052840598b7fa50c8af0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:12:56 +0000 Subject: [PATCH 39/73] ci(auto): record foundation compile result --- ANDROID_AUTO_BUILD_STATUS.md | 258 ++++++++++++++--------------------- 1 file changed, 102 insertions(+), 156 deletions(-) diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md index bbc3b8c2b0d..ca6bd247175 100644 --- a/ANDROID_AUTO_BUILD_STATUS.md +++ b/ANDROID_AUTO_BUILD_STATUS.md @@ -3,6 +3,29 @@ Result: **FAIL** ```text +Fetching distribution. +Downloading https://services.gradle.org/distributions/gradle-9.7.1-bin.zip +..............10%..............20%...............30%..............40%...............50%..............60%...............70%..............80%..............90%...............100% + +Welcome to Gradle 9.7.1! + +Here are the highlights of this release: + - Isolated Projects graduates to incubating + - Broader Configuration Cache compatibility + - Resilient Sync helps you fix broken builds + - More source locations in problem reports + +For more details see https://docs.gradle.org/9.7.1/release-notes.html + +Starting a Gradle Daemon (subsequent builds will be faster) +Configuration on demand is an incubating feature. + +> Configure project :app +WARNING: The option setting 'android.newDsl=false' is deprecated. +The current default is 'true'. +It will be removed in version 10.0 of the Android Gradle plugin. +Add android.sync.suppressAgpWarnings=UNSUPPORTED_PROJECT_OPTION_USE to the gradle.properties file to suppress this warning. +WARNING: The option setting 'android.enableJetifier=true' is deprecated. The current default is 'false'. It will be removed in version 10.0 of the Android Gradle plugin. Add android.sync.suppressAgpWarnings=UNSUPPORTED_PROJECT_OPTION_USE to the gradle.properties file to suppress this warning. @@ -16,39 +39,18 @@ w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_A > Task :app:preBuild UP-TO-DATE > Task :app:preGplayDebugBuild UP-TO-DATE > Task :app:dataBindingMergeDependencyArtifactsGplayDebug -WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/androidx.car.app/app/1.7.0/368eb3df2522b17368912c34129ebf3c1f0f9519/app-1.7.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. - Example of androidX reference: 'androidx/car/app/media/IMediaPlaybackHost' - Example of support library reference: 'android/support/v4/media/session/MediaSessionCompat$Token' -WARNING: [Processor] Library '/home/runner/.gradle/caches/modules-2/files-2.1/androidx.media3/media3-session/1.11.0/494cabd189f6ffa23a95603bdbf85c6a9d85a0e7/media3-session-1.11.0.aar' contains references to both AndroidX and old support library. This seems like the library is partially migrated. Jetifier will try to rewrite the library anyway. - Example of androidX reference: 'androidx/media3/session/legacy/MediaBrowserServiceCompat$2' - Example of support library reference: 'android/support/v4/media/MediaBrowserCompat$MediaItem' - -> Task :app:generateGplayDebugResources -> Task :app:generateGplayDebugBuildConfig -> Task :app:packageGplayDebugResources -> Task :app:processGplayDebugNavigationResources -> Task :app:parseGplayDebugLocalResources -> Task :app:mergeGplayDebugResources -> Task :app:generateGplayDebugRFile -> Task :app:dataBindingGenBaseClassesGplayDebug -> Task :app:kspGplayDebugKotlin -> Task :app:kaptGenerateStubsGplayDebugKotlin - -> Task :app:kaptGplayDebugKotlin -warning: The following options were not recognized by any processor: '[room.schemaLocation, kapt.kotlin.generated]' - -> Task :app:compileGplayDebugKotlin FAILED -e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:9:24 Unresolved reference 'ApplicationInfo'. -e: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt:32:40 Unresolved reference 'ApplicationInfo'. +> Task :app:dataBindingMergeDependencyArtifactsGplayDebug FAILED [Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html FAILURE: Build failed with an exception. * What went wrong: -Execution failed for task ':app:compileGplayDebugKotlin' (registered by plugin 'com.android.internal.application'). -> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork - > Compilation error. See log for more details +Execution failed for task ':app:dataBindingMergeDependencyArtifactsGplayDebug' (registered by plugin 'com.android.internal.application'). +> Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. + > Could not find androidx.core:core-telecom:1.1.0-beta01. + Required by: + project ':app' * Try: > Run with --info or --debug option to get more log output. @@ -56,17 +58,8 @@ Execution failed for task ':app:compileGplayDebugKotlin' (registered by plugin ' > Get more help at https://help.gradle.org. * Exception is: -org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:compileGplayDebugKotlin' (registered by plugin 'com.android.internal.application'). - at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:135) - at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:288) - at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:133) - at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:121) - at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41) - at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) - at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) - at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) - at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) - at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) +org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:dataBindingMergeDependencyArtifactsGplayDebug' (registered by plugin 'com.android.internal.application'). + at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) @@ -88,41 +81,64 @@ org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:com at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:328) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459) at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376) - at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) - at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) -Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionException: A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork - at org.gradle.workers.internal.DefaultWorkerExecutor$WorkItemExecution.waitForCompletion(DefaultWorkerExecutor.java:273) - at org.gradle.internal.work.DefaultAsyncWorkTracker.lambda$waitForItemsAndGatherFailures$2(DefaultAsyncWorkTracker.java:132) - at org.gradle.internal.Factories$1.create(Factories.java:30) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withoutLocksBlocking$0(DefaultWorkerLeaseService.java:412) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.withoutLocksBlocking(DefaultWorkerLeaseService.java:407) - at org.gradle.internal.work.DefaultWorkerLeaseService.blocking(DefaultWorkerLeaseService.java:257) - at org.gradle.internal.work.DefaultWorkerLeaseService.blocking(DefaultWorkerLeaseService.java:239) - at org.gradle.internal.work.DefaultAsyncWorkTracker.lambda$waitForItemsAndGatherFailures$1(DefaultAsyncWorkTracker.java:128) - at org.gradle.internal.Factories$1.create(Factories.java:30) - at org.gradle.internal.resources.AbstractResourceLockRegistry.whileDisallowingLockChanges(AbstractResourceLockRegistry.java:51) - at org.gradle.internal.work.DefaultWorkerLeaseService.whileDisallowingProjectLockChanges(DefaultWorkerLeaseService.java:262) - at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForItemsAndGatherFailures(DefaultAsyncWorkTracker.java:127) - at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForItemsAndGatherFailures(DefaultAsyncWorkTracker.java:93) - at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForAll(DefaultAsyncWorkTracker.java:79) - at org.gradle.internal.work.DefaultAsyncWorkTracker.waitForCompletion(DefaultAsyncWorkTracker.java:67) - at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:267) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) + at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:111) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:146) + at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:131) + at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:35) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:54) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:43) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) + at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) - at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:244) - at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:227) - at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:210) - at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:176) - at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:167) - at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:47) - at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:137) - at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:134) + at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) + at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:40) + at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$executeTasks$0(DefaultBuildLifecycleController.java:323) + at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) + at org.gradle.internal.model.StateTransitionController.lambda$tryTransition$0(StateTransitionController.java:235) + at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) + at org.gradle.internal.model.StateTransitionController.tryTransition(StateTransitionController.java:235) + at org.gradle.internal.build.DefaultBuildLifecycleController.executeTasks(DefaultBuildLifecycleController.java:314) + at org.gradle.internal.build.DefaultBuildWorkGraphController$DefaultBuildWorkGraph.runWork(DefaultBuildWorkGraphController.java:220) + at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) + at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) + at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) + at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) + at org.gradle.composite.internal.DefaultBuildController.doRun(DefaultBuildController.java:182) + at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.lambda$run$0(DefaultBuildController.java:199) + at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) + at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.run(DefaultBuildController.java:199) + at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) + at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) +Caused by: org.gradle.api.internal.artifacts.ivyservice.TypedResolveException: Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. + at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailure(ResolveExceptionMapper.java:73) + at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailures(ResolveExceptionMapper.java:65) + at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$DefaultResolutionHost.consolidateFailures(DefaultConfiguration.java:1801) + at org.gradle.api.internal.artifacts.configurations.ResolutionHost.rethrowFailuresAndReportProblems(ResolutionHost.java:75) + at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.maybeThrowResolutionFailures(ResolutionBackedFileCollection.java:86) + at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:76) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) + at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:112) + at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:66) + at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:91) + at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:311) + at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:112) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) + at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:112) + at org.gradle.api.internal.tasks.PropertyFileCollection.visitChildren(PropertyFileCollection.java:48) + at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:112) + at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) + at org.gradle.internal.fingerprint.impl.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:48) + at org.gradle.internal.execution.impl.DefaultInputFingerprinter$InputCollectingVisitor.visitInputFileProperty(DefaultInputFingerprinter.java:151) + at org.gradle.api.internal.tasks.execution.TaskExecution.visitMutableInputs(TaskExecution.java:345) + at org.gradle.internal.execution.impl.DefaultInputFingerprinter.fingerprintInputProperties(DefaultInputFingerprinter.java:77) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.captureExecutionStateWithOutputs(CaptureMutableStateBeforeExecutionStep.java:124) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.lambda$captureExecutionState$0(CaptureMutableStateBeforeExecutionStep.java:94) + at org.gradle.internal.execution.steps.BuildOperationStep$1.call(BuildOperationStep.java:38) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) @@ -130,59 +146,13 @@ Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionExcept at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:134) - at org.gradle.internal.execution.steps.ExecuteStep$Mutable.execute(ExecuteStep.java:80) - at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:42) - at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:75) - at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55) - at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:51) - at org.gradle.internal.execution.steps.PreCreateOutputParentsStep.execute(PreCreateOutputParentsStep.java:29) - at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.executeMutable(RemovePreviousOutputsStep.java:67) - at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.executeMutable(RemovePreviousOutputsStep.java:39) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:42) - at org.gradle.internal.execution.steps.BroadcastChangingOutputsStep.execute(BroadcastChangingOutputsStep.java:24) - at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:69) - at org.gradle.internal.execution.steps.CaptureOutputsAfterExecutionStep.execute(CaptureOutputsAfterExecutionStep.java:46) - at org.gradle.internal.execution.steps.ResolveInputChangesStep.executeMutable(ResolveInputChangesStep.java:39) - at org.gradle.internal.execution.steps.ResolveInputChangesStep.executeMutable(ResolveInputChangesStep.java:28) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:189) - at org.gradle.internal.execution.steps.BuildCacheStep.executeAndStoreInCache(BuildCacheStep.java:145) - at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$3(BuildCacheStep.java:104) - at org.gradle.internal.execution.steps.BuildCacheStep.lambda$executeWithCache$1(BuildCacheStep.java:104) - at org.gradle.internal.Try$Success.map(Try.java:170) - at org.gradle.internal.execution.steps.BuildCacheStep.executeWithCache(BuildCacheStep.java:88) - at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$0(BuildCacheStep.java:75) - at org.gradle.internal.Either$Left.fold(Either.java:116) - at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:62) - at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:74) - at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:49) - at org.gradle.internal.execution.steps.StoreExecutionStateStep.executeMutable(StoreExecutionStateStep.java:46) - at org.gradle.internal.execution.steps.StoreExecutionStateStep.executeMutable(StoreExecutionStateStep.java:35) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:75) - at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:53) - at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:53) - at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:35) - at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37) - at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27) - at org.gradle.internal.execution.steps.ResolveMutableCachingStateStep.executeDelegate(ResolveMutableCachingStateStep.java:70) - at org.gradle.internal.execution.steps.ResolveMutableCachingStateStep.executeDelegate(ResolveMutableCachingStateStep.java:32) - at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:69) - at org.gradle.internal.execution.steps.AbstractResolveCachingStateStep.execute(AbstractResolveCachingStateStep.java:37) - at org.gradle.internal.execution.steps.ResolveChangesStep.executeMutable(ResolveChangesStep.java:63) - at org.gradle.internal.execution.steps.ResolveChangesStep.executeMutable(ResolveChangesStep.java:34) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.ValidateStep$Mutable.executeDelegate(ValidateStep.java:79) - at org.gradle.internal.execution.steps.ValidateStep$Mutable.executeDelegate(ValidateStep.java:65) - at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:105) - at org.gradle.internal.execution.steps.ValidateStep$Mutable.execute(ValidateStep.java:65) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.executeMutable(CaptureMutableStateBeforeExecutionStep.java:86) + at org.gradle.internal.execution.steps.BuildOperationStep.operation(BuildOperationStep.java:35) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.captureExecutionState(CaptureMutableStateBeforeExecutionStep.java:92) + at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.executeMutable(CaptureMutableStateBeforeExecutionStep.java:73) at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:65) at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:45) at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeWithNonEmptySources(SkipEmptyMutableWorkStep.java:210) - at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:90) + at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:85) at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:53) at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) @@ -208,41 +178,17 @@ Caused by: org.gradle.workers.internal.DefaultWorkerExecutor$WorkExecutionExcept at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:38) at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:68) at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:132) - ... 30 more -Caused by: org.jetbrains.kotlin.gradle.tasks.CompilationErrorException: Compilation error. See log for more details - at org.jetbrains.kotlin.gradle.tasks.TasksUtilsKt.throwExceptionIfCompilationFailed(tasksUtils.kt:21) - at org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork.execute(BuildToolsApiCompilationWork.kt:320) - at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68) - at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64) - at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61) - at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:103) - at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61) - at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44) - at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41) - at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58) - at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$1(DefaultWorkerExecutor.java:169) - at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:191) - at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$600(DefaultConditionalExecutionQueue.java:112) - at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:168) - at org.gradle.internal.Factories$1.create(Factories.java:30) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:137) - at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:163) - at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:125) - ... 2 more + at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:121) + at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41) + at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) + at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) + at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) + at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) + at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) + ... 54 more +Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find androidx.core:core-telecom:1.1.0-beta01. +Required by: + project ':app' Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. @@ -251,6 +197,6 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 6m -13 actionable tasks: 13 executed +BUILD FAILED in 2m 2s +1 actionable task: 1 executed ``` From 116822533d854e5cef7b1300f5979e19ae3ab0a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:12:31 +0000 Subject: [PATCH 40/73] feat(auto): wire Talk calls to published Core-Telecom --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 05d3a4b4be5..a861ffc8588 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -197,7 +197,7 @@ 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-beta01") + "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") From b9707538f296d1cf01df77c73be6a1cbad8e3797 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2026 20:18:59 +0000 Subject: [PATCH 41/73] ci(auto): record call bridge compile result --- ANDROID_AUTO_CALL_BUILD_STATUS.md | 466 +++++++++++++++--------------- 1 file changed, 233 insertions(+), 233 deletions(-) diff --git a/ANDROID_AUTO_CALL_BUILD_STATUS.md b/ANDROID_AUTO_CALL_BUILD_STATUS.md index 3a803ad7b25..3f644c333b7 100644 --- a/ANDROID_AUTO_CALL_BUILD_STATUS.md +++ b/ANDROID_AUTO_CALL_BUILD_STATUS.md @@ -1,239 +1,238 @@ # Android Auto call bridge build -Result: **FAIL** +Result: **PASS** ```text - at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2$1.accept(WorkNodeCodec.kt:399) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2$1.accept(WorkNodeCodec.kt:398) - at org.gradle.api.internal.project.DefaultProjectState.lambda$applyToMutableState$0(DefaultProjectState.java:241) - at org.gradle.api.internal.project.DefaultProjectState.lambda$fromMutableState$0(DefaultProjectState.java:248) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withReplacedLocks$0(DefaultWorkerLeaseService.java:452) - at org.gradle.internal.work.DefaultWorkerLeaseService.withoutLocks(DefaultWorkerLeaseService.java:374) - at org.gradle.internal.work.DefaultWorkerLeaseService.withReplacedLocks(DefaultWorkerLeaseService.java:451) - at org.gradle.api.internal.project.DefaultProjectState.runWithModelLock(DefaultProjectState.java:276) - at org.gradle.api.internal.project.DefaultProjectState.fromMutableState(DefaultProjectState.java:248) - at org.gradle.api.internal.project.DefaultProjectState.applyToMutableState(DefaultProjectState.java:240) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invokeSuspend(WorkNodeCodec.kt:398) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invoke(WorkNodeCodec.kt) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$safeRunnerFor$2.invoke(WorkNodeCodec.kt) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invokeSuspend(WorkNodeCodec.kt:331) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invoke(WorkNodeCodec.kt) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$writeGroupedNodes$1.invoke(WorkNodeCodec.kt) - at org.gradle.internal.serialize.graph.RunningKt$runWriteOperation$1.invokeSuspend(Running.kt:43) - at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34) - at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115) - at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) - at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeGroupedNodes(WorkNodeCodec.kt:327) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodeBatchesInParallel$lambda$1$0$0(WorkNodeCodec.kt:248) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec$runBuildOperations$1$1.execute$lambda$1(WorkNodeCodec.kt:597) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodecKt$asBuildOperation$1.run(WorkNodeCodec.kt:640) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationExecutor.lambda$executeInParallel$0(DefaultBuildOperationExecutor.java:106) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:416) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.doRunBatch(DefaultBuildOperationQueue.java:407) - at org.gradle.internal.operations.DefaultBuildOperationQueue.withProjectLockChangePolicy(DefaultBuildOperationQueue.java:209) - at org.gradle.internal.operations.DefaultBuildOperationQueue.access$900(DefaultBuildOperationQueue.java:38) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.executePendingWork(DefaultBuildOperationQueue.java:378) - at org.gradle.internal.work.DefaultWorkerLeaseService.tryRunAsWorkerThread(DefaultWorkerLeaseService.java:145) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runBatchWithLeaseRetry$0(DefaultBuildOperationQueue.java:353) - at org.gradle.internal.time.ExponentialBackoff.retryUntil(ExponentialBackoff.java:69) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatchWithLeaseRetry(DefaultBuildOperationQueue.java:352) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:338) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.lambda$runOperations$0(DefaultBuildOperationQueue.java:269) - at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperations(DefaultBuildOperationQueue.java:266) - at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$000(DefaultBuildOperationQueue.java:245) - at org.gradle.internal.operations.DefaultBuildOperationQueue.waitForCompletion(DefaultBuildOperationQueue.java:146) - at org.gradle.internal.operations.DefaultBuildOperationExecutor.executeInParallel(DefaultBuildOperationExecutor.java:119) - at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAllWithAccessToProjectState(DefaultBuildOperationExecutor.java:83) - at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAllWithAccessToProjectState(DefaultBuildOperationExecutor.java:78) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.runBuildOperations$lambda$0(WorkNodeCodec.kt:588) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.handleBuildOperationExceptions(WorkNodeCodec.kt:286) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.runBuildOperations(WorkNodeCodec.kt:587) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodeBatchesInParallel(WorkNodeCodec.kt:243) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeNodes(WorkNodeCodec.kt:209) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.doWrite(WorkNodeCodec.kt:122) - at org.gradle.internal.serialize.codecs.core.WorkNodeCodec.writeWork(WorkNodeCodec.kt:94) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeWorkGraphOf(ConfigurationCacheState.kt:570) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildContent$org_gradle_configuration_cache(ConfigurationCacheState.kt:524) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildState(ConfigurationCacheState.kt:363) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeBuildsInTree(ConfigurationCacheState.kt:314) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeRootBuild(ConfigurationCacheState.kt:287) - at org.gradle.internal.cc.impl.ConfigurationCacheState.writeRootBuildState(ConfigurationCacheState.kt:185) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invokeSuspend(DefaultConfigurationCacheIO.kt:220) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invoke(DefaultConfigurationCacheIO.kt) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeRootBuildStateTo$1.invoke(DefaultConfigurationCacheIO.kt) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invokeSuspend(DefaultConfigurationCacheIO.kt:369) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invoke(DefaultConfigurationCacheIO.kt) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO$writeConfigurationCacheStateWithSpecialEncoders$1.invoke(DefaultConfigurationCacheIO.kt) - at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invokeSuspend(Codec.kt:84) - at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invoke(Codec.kt) - at org.gradle.internal.serialize.graph.CodecKt$writeWith$1$1.invoke(Codec.kt) - at org.gradle.internal.serialize.graph.RunningKt$runWriteOperation$1.invokeSuspend(Running.kt:43) - at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34) - at kotlin.coroutines.ContinuationKt.startCoroutine(Continuation.kt:115) - at org.gradle.internal.serialize.graph.RunningKt.runToCompletion(Running.kt:58) - at org.gradle.internal.serialize.graph.RunningKt.runWriteOperation(Running.kt:42) - at org.gradle.internal.serialize.graph.CodecKt.writeWith(Codec.kt:83) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:521) - at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor(ConfigurationCacheBuildTreeIO.kt:131) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withWriteContextFor(DefaultConfigurationCacheIO.kt:101) - at org.gradle.internal.cc.impl.ConfigurationCacheBuildTreeIO.withWriteContextFor$default(ConfigurationCacheBuildTreeIO.kt:124) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheStateWithSpecialEncoders(DefaultConfigurationCacheIO.kt:368) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0$0(DefaultConfigurationCacheIO.kt:272) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withSharedObjectEncoderFor(DefaultConfigurationCacheIO.kt:331) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState$lambda$0(DefaultConfigurationCacheIO.kt:271) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.withStringEncoderFor(DefaultConfigurationCacheIO.kt:319) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeConfigurationCacheState(DefaultConfigurationCacheIO.kt:270) - at org.gradle.internal.cc.impl.DefaultConfigurationCacheIO.writeRootBuildStateTo(DefaultConfigurationCacheIO.kt:218) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.writeConfigurationCacheState(DefaultConfigurationCache.kt:803) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0$0(DefaultConfigurationCache.kt:717) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore$lambda$0(DefaultConfigurationCache.kt:732) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore$lambda$0(ConfigurationCacheRepository.kt:255) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$withExclusiveAccessToCache$1.get(ConfigurationCacheRepository.kt:321) - at org.gradle.cache.internal.LockOnDemandCrossProcessCacheAccess.withFileLock(LockOnDemandCrossProcessCacheAccess.java:90) - at org.gradle.cache.internal.DefaultCacheCoordinator.withFileLock(DefaultCacheCoordinator.java:226) - at org.gradle.cache.internal.DefaultPersistentDirectoryStore.withFileLock(DefaultPersistentDirectoryStore.java:148) - at org.gradle.cache.internal.DefaultCacheFactory$ReferenceTrackingPersistentCache.withFileLock(DefaultCacheFactory.java:245) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository.withExclusiveAccessToCache(ConfigurationCacheRepository.kt:319) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository.access$withExclusiveAccessToCache(ConfigurationCacheRepository.kt:54) - at org.gradle.internal.cc.impl.ConfigurationCacheRepository$StoreImpl.useForStore(ConfigurationCacheRepository.kt:245) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runAndStore(DefaultConfigurationCache.kt:729) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph$lambda$0(DefaultConfigurationCache.kt:716) - at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt$withWorkGraphStoreOperation$1.run(ConfigurationCacheBuildOperations.kt:63) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:30) - at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:27) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:48) - at org.gradle.internal.cc.operations.ConfigurationCacheBuildOperationsKt.withWorkGraphStoreOperation(ConfigurationCacheBuildOperations.kt:56) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.saveWorkGraph(DefaultConfigurationCache.kt:715) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1$0(DefaultConfigurationCache.kt:282) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.degradeGracefullyOr(DefaultConfigurationCache.kt:342) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks$lambda$1(DefaultConfigurationCache.kt:282) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.runWorkThatContributesToCacheEntry(DefaultConfigurationCache.kt:654) - at org.gradle.internal.cc.impl.DefaultConfigurationCache.loadOrScheduleRequestedTasks(DefaultConfigurationCache.kt:279) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:57) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1$result$1.call(ConfigurationCacheAwareBuildTreeWorkController.kt:56) - at org.gradle.internal.Try.ofFailable(Try.java:46) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:56) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController$scheduleAndRunRequestedTasks$executionResult$1.apply(ConfigurationCacheAwareBuildTreeWorkController.kt:55) - at org.gradle.composite.internal.DefaultIncludedBuildTaskGraph.withNewWorkGraph(DefaultIncludedBuildTaskGraph.java:115) - at org.gradle.internal.cc.impl.ConfigurationCacheAwareBuildTreeWorkController.scheduleAndRunRequestedTasks(ConfigurationCacheAwareBuildTreeWorkController.kt:55) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$scheduleAndRunTasks$0(DefaultBuildTreeLifecycleController.java:80) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.lambda$runBuild$0(DefaultBuildTreeLifecycleController.java:166) - at org.gradle.internal.model.StateTransitionController.lambda$transition$2(StateTransitionController.java:227) - at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) - at org.gradle.internal.model.StateTransitionController.lambda$transition$1(StateTransitionController.java:227) - at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) - at org.gradle.internal.model.StateTransitionController.transition(StateTransitionController.java:227) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.runBuild(DefaultBuildTreeLifecycleController.java:163) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:80) - at org.gradle.internal.buildtree.DefaultBuildTreeLifecycleController.scheduleAndRunTasks(DefaultBuildTreeLifecycleController.java:75) - at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:31) - at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) - at org.gradle.internal.buildtree.ProblemReportingBuildActionRunner.run(ProblemReportingBuildActionRunner.java:55) - at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:83) - at org.gradle.tooling.internal.provider.FileSystemWatchingBuildActionRunner.run(FileSystemWatchingBuildActionRunner.java:118) - at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:64) - at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.lambda$execute$0(RootBuildLifecycleBuildActionExecutor.java:97) - at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:119) - at org.gradle.launcher.exec.RootBuildLifecycleBuildActionExecutor.execute(RootBuildLifecycleBuildActionExecutor.java:97) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeLifecycle(DefaultBuildTreeActionExecutor.java:126) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.access$100(DefaultBuildTreeActionExecutor.java:52) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:98) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor$2.call(DefaultBuildTreeActionExecutor.java:94) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runAsBuildOperation(DefaultBuildTreeActionExecutor.java:94) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.lambda$runBuildTreeAction$0(DefaultBuildTreeActionExecutor.java:88) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) - at org.gradle.launcher.exec.DefaultBuildTreeActionExecutor.runBuildTreeAction(DefaultBuildTreeActionExecutor.java:88) - at org.gradle.tooling.internal.provider.continuous.ContinuousBuildActionExecutor.execute(ContinuousBuildActionExecutor.java:111) - at org.gradle.tooling.internal.provider.SubscribableBuildActionExecutor.execute(SubscribableBuildActionExecutor.java:64) - at org.gradle.internal.session.DefaultBuildSessionContext.execute(DefaultBuildSessionContext.java:46) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:106) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor$ActionImpl.apply(BuildSessionLifecycleBuildActionExecutor.java:94) - at org.gradle.internal.session.BuildSessionState.run(BuildSessionState.java:73) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:67) - at org.gradle.internal.buildprocess.execution.BuildSessionLifecycleBuildActionExecutor.execute(BuildSessionLifecycleBuildActionExecutor.java:45) - at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:57) - at org.gradle.internal.buildprocess.execution.StartParamsValidatingActionExecutor.execute(StartParamsValidatingActionExecutor.java:32) - at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:51) - at org.gradle.internal.buildprocess.execution.SessionFailureReportingActionExecutor.execute(SessionFailureReportingActionExecutor.java:39) - at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:47) - at org.gradle.internal.buildprocess.execution.SetupLoggingActionExecutor.execute(SetupLoggingActionExecutor.java:31) - at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:70) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:29) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ForwardClientInput.lambda$execute$0(ForwardClientInput.java:40) - at org.gradle.internal.daemon.clientinput.ClientInputForwarder.forwardInput(ClientInputForwarder.java:80) - at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:64) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.ApplyClientEnvironmentVariables.doBuild(ApplyClientEnvironmentVariables.java:80) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:74) - at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) - at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) - at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) - at org.gradle.launcher.daemon.server.DaemonStateCoordinator.lambda$runCommand$0(DaemonStateCoordinator.java:321) - at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) - at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) -Caused by: org.gradle.api.internal.artifacts.ivyservice.TypedResolveException: Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. - at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailure(ResolveExceptionMapper.java:73) - at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailures(ResolveExceptionMapper.java:65) - at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$DefaultResolutionHost.consolidateFailures(DefaultConfiguration.java:1801) - at org.gradle.api.internal.artifacts.configurations.ResolutionHost.rethrowFailuresAndReportProblems(ResolutionHost.java:75) - at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.maybeThrowResolutionFailures(ResolutionBackedFileCollection.java:86) - at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:76) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) - at org.gradle.internal.serialize.codecs.core.CollectingVisitor.startVisit(FileCollectionCodec.kt:208) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:357) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeViaCollectingVisitor(FileCollectionCodec.kt:81) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encodeContents(FileCollectionCodec.kt:74) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:63) - at org.gradle.internal.serialize.codecs.core.FileCollectionCodec.encode(FileCollectionCodec.kt:55) - at org.gradle.internal.serialize.graph.codecs.BindingsBackedCodec.encode(BindingsBackedCodec.kt:66) - at org.gradle.internal.serialize.graph.DefaultWriteContext.write(Contexts.kt:111) - at org.gradle.internal.serialize.graph.BeanPropertyExtensionsKt.writePropertyValue(BeanPropertyExtensions.kt:34) - ... 230 more -Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find androidx.core:core-telecom:1.1.0-beta01. -Required by: - project ':app' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:432:41 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:435:71 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:492:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:497:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:523:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:528:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:740:46 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:745:48 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:759:13 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:760:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:819:38 Unnecessary safe call on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:908:78 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:911:13 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:912:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:914:59 Unnecessary safe call on a non-null receiver of type 'EmojiEditText'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:928:50 Elvis operator (?:) always returns the left operand of non-nullable type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:948:56 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:951:46 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:955:56 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:1040:60 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:1089:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt:83:20 'constructor(): MediaRecorder' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:513:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:514:17 'fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow' is deprecated. use getChatMessageEntity. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:546:31 'fun getSerializable(p0: String?): Serializable?' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:546:73 Unchecked cast of 'Serializable?' to 'HashMap'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:797:45 'fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow' is deprecated. use getChatMessageEntity. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:904:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:928:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt:82:9 The corresponding parameter in the supertype 'ChatNetworkDataSource' is named 'apiVersion'. This may cause problems when calling this function with named arguments. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt:97:9 The corresponding parameter in the supertype 'ChatNetworkDataSource' is named 'apiVersion'. This may cause problems when calling this function with named arguments. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:533:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:609:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:980:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1010:29 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1020:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1026:22 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1057:14 This declaration is in a preview state and can be changed in a backwards-incompatible manner with a best-effort migration. Its usage should be marked with '@kotlinx.coroutines.FlowPreview' or '@OptIn(kotlinx.coroutines.FlowPreview::class)' if you accept the drawback of relying on preview API +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1058:23 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1072:46 Elvis operator (?:) always returns the left operand of non-nullable type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1123:14 This declaration is in a preview state and can be changed in a backwards-incompatible manner with a best-effort migration. Its usage should be marked with '@kotlinx.coroutines.FlowPreview' or '@OptIn(kotlinx.coroutines.FlowPreview::class)' if you accept the drawback of relying on preview API +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1154:40 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1527:19 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1529:17 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1538:9 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1560:32 'fun getRoom(user: User, roomToken: String): Job' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1560:40 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1742:62 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1897:20 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1906:22 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1940:17 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1972:51 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1972:73 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1974:23 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1983:21 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2001:51 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2001:73 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2003:23 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2012:21 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2130:45 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2205:51 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2215:13 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2215:24 Unnecessary safe call on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2221:51 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2353:20 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2357:21 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2358:21 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2366:44 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2367:13 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2377:48 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2378:17 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2389:44 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2390:13 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2401:48 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2402:17 'var currentUser: User' is deprecated. use currentUserFlow. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2416:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2426:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2434:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2441:13 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ScheduledMessagesViewModel.kt:242:28 'suspend fun getParentMessageById(messageId: Long): Flow' is deprecated. getMessage(messageId: Long, bundle: Bundle). +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/ChooseAccountDialogCompose.kt:111:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/viewmodel/StatusMessageViewModel.kt:39:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/viewmodel/StatusViewModel.kt:25:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/components/ColoredStatusBar.kt:54:25 'var statusBarColor: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/components/StandardAppBar.kt:75:34 Unnecessary safe call on a non-null receiver of type 'List Unit>>'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt:32:62 Java type mismatch: inferred type is 'MutableMap?', but '(Mutable)Map' was expected. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt:84:66 Java type mismatch: inferred type is 'MutableMap?', but '(Mutable)Map' was expected. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationcreation/viewmodel/ConversationCreationViewModel.kt:31:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationcreation/viewmodel/ConversationCreationViewModel.kt:174:25 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:507:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:665:19 'fun demoteModeratorToUser(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:668:29 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:671:19 'fun promoteUserToModerator(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:674:29 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:706:23 'fun removeParticipantFromConversation(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:708:30 'fun getUrlForRemovingParticipantFromConversation(baseUrl: String?, roomToken: String?, isGuest: Boolean): String' is deprecated. This is only supported on API v1-3, in API v4+ please use {@link ApiUtils#getUrlForAttendees(int, String, String)} instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:709:33 'var sessionId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:712:23 'fun removeParticipantFromConversation(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:714:30 'fun getUrlForRemovingParticipantFromConversation(baseUrl: String?, roomToken: String?, isGuest: Boolean): String' is deprecated. This is only supported on API v1-3, in API v4+ please use {@link ApiUtils#getUrlForAttendees(int, String, String)} instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:715:33 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ParticipantItemAdapter.kt:252:35 'fun getColor(p0: Int): Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:330:58 Elvis operator (?:) always returns the left operand of non-nullable type 'Long'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:331:35 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:355:13 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:202:13 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1221:48 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1221:76 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1236:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1481:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:81:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:105:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:114:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:162:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ui/ConversationListItem.kt:114:55 'var activeUser: User?' is deprecated. should be deleted in long term. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:74:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:408:49 Unnecessary safe call on a non-null receiver of type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:537:30 'fun getRooms(user: User): Job' is deprecated. use observeConversation. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationtags/viewmodels/ConversationTagsViewModel.kt:38:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt:53:98 Unchecked cast of 'ViewModel?' to 'T (of fun create)'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/data/source/local/converters/HashMapHashMapConverter.kt:29:65 Unchecked cast of '(Mutable)Map!>!' to 'HashMap>?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisViewModel.kt:25:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt:139:17 'var activeUser: User?' is deprecated. should be deleted in long term. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt:140:17 'var activeUser: User?' is deprecated. should be deleted in long term. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/filebrowser/webdav/ReadFolderListingOperation.kt:84:17 Expression is unused. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/invitation/InvitationsActivity.kt:62:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:62:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:467:29 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:487:22 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:499:18 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/DownloadFileToCacheWorker.kt:45:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt:49:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt:53:21 Condition is always 'true'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt:125:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:89:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:557:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:572:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/components/LocationPickerScreen.kt:151:50 Unnecessary non-null assertion (!!) on a non-null receiver of type 'GeocodingResult'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/components/LocationPickerScreen.kt:151:86 Unnecessary non-null assertion (!!) on a non-null receiver of type 'GeocodingResult'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/viewmodels/LocationPickerViewModel.kt:37:41 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/lock/LockedActivity.kt:128:39 'fun createConfirmDeviceCredentialIntent(p0: CharSequence!, p1: CharSequence!): Intent!' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt:76:16 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt:40:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/domain/converters/DomainEnumNotificationLevelConverter.kt:30:13 'when' is exhaustive so 'else' is redundant here. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt:94:17 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt:108:13 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:92:40 Unnecessary safe call on a non-null receiver of type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:96:39 Unnecessary safe call on a non-null receiver of type 'Boolean'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:97:42 Unnecessary safe call on a non-null receiver of type 'Boolean'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:98:47 Unnecessary safe call on a non-null receiver of type 'Boolean'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:101:42 Unnecessary safe call on a non-null receiver of type 'Long'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/openconversations/ListOpenConversationsActivity.kt:43:20 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt:38:30 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt:175:24 'fun bundleOf(vararg pairs: Pair): Bundle' is deprecated. This method does not provide type safety at compile time. Use the platform `Bundle` class directly instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt:26:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt:26:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt:175:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt:53:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/DismissRecordingAvailableReceiver.kt:38:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt:40:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/ShareRecordingToChatReceiver.kt:41:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt:55:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt:30:59 Unchecked cast of 'Any!' to 'List'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt:52:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:340:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:660:13 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:667:17 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt:82:20 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt:106:77 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:323:53 Unchecked cast of 'Any?' to 'Map?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:384:49 Unchecked cast of 'Any?' to 'Map?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:470:40 Unchecked cast of 'Any?' to 'List>?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:517:40 Unchecked cast of 'Map' to 'Map'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:546:21 'var sessionId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:549:25 'var userId: String?' is deprecated. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/threadsoverview/viewmodels/ThreadsOverviewViewModel.kt:30:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt:28:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/chat/MediaMessage.kt:286:69 No cast needed. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimeCompose.kt:95:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/DialogBanListFragment.kt:44:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:38:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:49:79 Unchecked cast of 'HashMap<*, *>?' to 'HashMap'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:51:24 'fun getSerializable(p0: String?): Serializable?' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:51:58 Unchecked cast of 'Serializable?' to 'HashMap'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt:105:61 Unnecessary safe call on a non-null receiver of type 'User'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt:105:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt:19:31 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:100:20 'static fun setBackground(p0: View, p1: Drawable?): Unit' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:124:24 'static fun setBackground(p0: View, p1: Drawable?): Unit' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:434:59 'var activeUser: User?' is deprecated. should be deleted in long term. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt:141:17 Expression is unused. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt:129:25 'fun create(contentType: MediaType?, content: ByteArray, offset: Int = ..., byteCount: Int = ...): RequestBody' is deprecated. Moved to extension function. Put the 'content' argument first to fix Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:104:29 'field versionCode: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:105:91 'static field GET_SIGNATURES: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:105:107 'field signatures: Array<(out) Signature!>?' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:108:36 'static field GET_SIGNATURES: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:109:19 'field signatures: Array<(out) Signature!>?' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:152:25 'fun getColor(p0: Int): Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:313:26 'static field SYSTEM_UI_FLAG_LIGHT_STATUS_BAR: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:314:30 'static field SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:316:23 'var systemUiVisibility: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:318:23 'var systemUiVisibility: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:320:20 'var statusBarColor: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:346:16 'var navigationBarColor: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt:322:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt:325:36 The corresponding parameter in the supertype 'Observer' is named 'value'. This may cause problems when calling this function with named arguments. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt:60:38 'static fun createWrapper(p0: InputConnection, p1: EditorInfo, p2: InputConnectionCompat.OnCommitContentListener): InputConnection' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt:101:43 'static field USAGE_NOTIFICATION_COMMUNICATION_REQUEST: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt:122:43 'static field USAGE_NOTIFICATION_COMMUNICATION_INSTANT: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt:81:21 'fun tryPickDistributor(context: Context, callback: (Boolean) -> Unit): Unit' is deprecated. Use tryPickDistributor(activity, callback) instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/VibrationUtils.kt:17:57 'static field VIBRATOR_SERVICE: String' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderOldImpl.kt:22:94 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/UserModule.kt:23:37 'class CurrentUserProviderOldImpl : CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/UserModule.kt:24:8 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:45:26 'static field SCREEN_BRIGHT_WAKE_LOCK: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:45:66 'static field ACQUIRE_CAUSES_WAKEUP: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:55:50 'static field WIFI_MODE_FULL_HIGH_PERF: Int' is deprecated. Deprecated in Java. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:152:13 'when' is exhaustive so 'else' is redundant here. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtils.kt:96:23 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtils.kt:97:17 'constructor(userManager: UserManager): CurrentUserProviderOldImpl' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:62:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:72:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:74:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:255:80 Unchecked cast of 'Any?' to 'List>?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:260:51 Unchecked cast of 'Any?' to 'HashMap?'. +w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:279:82 Unchecked cast of 'Any?' to 'List?'. +[Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. @@ -241,6 +240,7 @@ You can use '--warning-mode all' to show the individual deprecation warnings and For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. -BUILD FAILED in 1m 26s -Configuration cache entry discarded due to serialization error. +BUILD SUCCESSFUL in 6m 27s +13 actionable tasks: 13 executed +Configuration cache entry stored. ``` From ba4fe8803ce657d9c7d0ead22e4669abe0709afb Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:29:22 -0400 Subject: [PATCH 42/73] ci(auto): replace bootstrap workflows with stable build check --- .../android-auto-apply-bootstrap.yml | 37 --- .../android-auto-apply-call-bridge.yml | 79 ----- .../android-auto-bootstrap-car-service.yml | 274 ------------------ .github/workflows/android-auto-build.yml | 34 +++ .../android-auto-fix-verification.yml | 68 ----- .../workflows/android-auto-import-pr6012.yml | 58 ---- .../android-auto-update-verification.yml | 46 --- .../android-auto-validate-foundation.yml | 65 ----- .../android-auto-wire-call-bridge.yml | 142 --------- ANDROID_AUTO_BUILD_STATUS.md | 202 ------------- ANDROID_AUTO_CALL_BUILD_STATUS.md | 246 ---------------- 11 files changed, 34 insertions(+), 1217 deletions(-) delete mode 100644 .github/workflows/android-auto-apply-bootstrap.yml delete mode 100644 .github/workflows/android-auto-apply-call-bridge.yml delete mode 100644 .github/workflows/android-auto-bootstrap-car-service.yml create mode 100644 .github/workflows/android-auto-build.yml delete mode 100644 .github/workflows/android-auto-fix-verification.yml delete mode 100644 .github/workflows/android-auto-import-pr6012.yml delete mode 100644 .github/workflows/android-auto-update-verification.yml delete mode 100644 .github/workflows/android-auto-validate-foundation.yml delete mode 100644 .github/workflows/android-auto-wire-call-bridge.yml delete mode 100644 ANDROID_AUTO_BUILD_STATUS.md delete mode 100644 ANDROID_AUTO_CALL_BUILD_STATUS.md diff --git a/.github/workflows/android-auto-apply-bootstrap.yml b/.github/workflows/android-auto-apply-bootstrap.yml deleted file mode 100644 index 0d87a77f3b3..00000000000 --- a/.github/workflows/android-auto-apply-bootstrap.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Android Auto - apply bootstrap - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-apply-bootstrap.yml - -permissions: - contents: write - -jobs: - apply: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Apply Android Auto bootstrap - run: python3 tools/android_auto_bootstrap.py - - - name: Commit generated changes - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/build.gradle.kts app/src/gplay - if git diff --cached --quiet; then - echo "Bootstrap already applied." - exit 0 - fi - git commit -m "feat(auto): add Car App and Telecom foundation" - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-apply-call-bridge.yml b/.github/workflows/android-auto-apply-call-bridge.yml deleted file mode 100644 index 35722d8d186..00000000000 --- a/.github/workflows/android-auto-apply-call-bridge.yml +++ /dev/null @@ -1,79 +0,0 @@ -name: Android Auto - apply call bridge - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-apply-call-bridge.yml - pull_request: - branches: - - master - paths: - - .github/workflows/android-auto-apply-call-bridge.yml - -permissions: - contents: write - -jobs: - apply-and-build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Apply Android Auto source and published dependency patches - run: | - python3 scripts/android-auto-wire-call-bridge.py - python3 scripts/android-auto-update-dependencies.py - - - name: Commit wiring and dependency update - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/build.gradle.kts \ - app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ - app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt - if ! git diff --cached --quiet; then - git commit -m "feat(auto): wire Talk calls to published Core-Telecom" - fi - git fetch origin android-auto - git rebase origin/android-auto - - - name: Compile gplay debug Kotlin - id: compile - run: | - set +e - ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-call-build.log 2>&1 - rc=$? - echo "rc=$rc" >> "$GITHUB_OUTPUT" - exit 0 - - - name: Record compiler result - run: | - set -euo pipefail - rc='${{ steps.compile.outputs.rc }}' - if [ "$rc" = "0" ]; then result="PASS"; else result="FAIL"; fi - { - echo "# Android Auto call bridge build" - echo - echo "Result: **$result**" - echo - echo '```text' - tail -n 240 /tmp/android-auto-call-build.log - echo '```' - } > ANDROID_AUTO_CALL_BUILD_STATUS.md - git add ANDROID_AUTO_CALL_BUILD_STATUS.md - if ! git diff --cached --quiet; then - git commit -m "ci(auto): record call bridge compile result" - fi - - - name: Rebase and push results - run: | - set -euo pipefail - git fetch origin android-auto - git rebase origin/android-auto - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-bootstrap-car-service.yml b/.github/workflows/android-auto-bootstrap-car-service.yml deleted file mode 100644 index 08cb0d1abf5..00000000000 --- a/.github/workflows/android-auto-bootstrap-car-service.yml +++ /dev/null @@ -1,274 +0,0 @@ -name: Android Auto - bootstrap car service - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-bootstrap-car-service.yml - -permissions: - contents: write - -jobs: - bootstrap: - runs-on: ubuntu-latest - steps: - - name: Check out Android Auto branch - uses: actions/checkout@v6 - with: - fetch-depth: 0 - ref: android-auto - - - name: Add Android Auto Car App and Telecom foundation - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - from pathlib import Path - - gradle = Path('app/build.gradle.kts') - text = gradle.read_text() - anchor = 'dependencies {\n implementation("androidx.media3:media3-session:1.11.0")\n' - addition = '''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") -''' - if 'androidx.car.app:app:1.7.0' not in text: - if anchor not in text: - raise SystemExit('Could not find dependencies anchor in app/build.gradle.kts') - text = text.replace(anchor, addition, 1) - gradle.write_text(text) - - manifest = Path('app/src/gplay/AndroidManifest.xml') - text = manifest.read_text() - if 'android.permission.MANAGE_OWN_CALLS' not in text: - marker = '\n' - replacement = marker + '\n \n' - if marker not in text: - raise SystemExit('Could not find gplay manifest root') - text = text.replace(marker, replacement, 1) - - if 'androidx.car.app.minCarApiLevel' not in text: - marker = ' \n' - replacement = marker + ''' - - - -''' - if marker not in text: - raise SystemExit('Could not find gplay application metadata anchor') - text = text.replace(marker, replacement, 1) - - if '.auto.TalkCarAppService' not in text: - marker = ' - - - - - - - -''' - if marker not in text: - raise SystemExit('Could not find service anchor in gplay manifest') - text = text.replace(marker, service + marker, 1) - manifest.write_text(text) - - descriptor = Path('app/src/gplay/res/xml/automotive_app_desc.xml') - text = descriptor.read_text() - if '' not in text: - text = text.replace(' \n', ' \n \n', 1) - descriptor.write_text(text) - - service_file = Path('app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt') - service_file.parent.mkdir(parents=True, exist_ok=True) - service_file.write_text('''/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2026 Michael Avery - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package com.nextcloud.talk.auto - -import android.content.ApplicationInfo -import android.content.Intent -import androidx.car.app.CarAppService -import androidx.car.app.CarContext -import androidx.car.app.Screen -import androidx.car.app.Session -import androidx.car.app.model.Action -import androidx.car.app.model.Header -import androidx.car.app.model.ItemList -import androidx.car.app.model.ListTemplate -import androidx.car.app.model.Row -import androidx.car.app.model.Template -import androidx.car.app.validation.HostValidator -import com.nextcloud.talk.auto.call.TalkTelecomManager - -/** Android Auto entry point for Talk messaging and calling. */ -class TalkCarAppService : CarAppService() { - override fun onCreate() { - super.onCreate() - TalkTelecomManager.get(applicationContext).registerWithTelecom() - } - - override fun createHostValidator(): HostValidator = - if ((applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) != 0) { - HostValidator.ALLOW_ALL_HOSTS_VALIDATOR - } else { - HostValidator.Builder(this) - .addAllowedHosts(androidx.car.app.R.array.hosts_allowlist_sample) - .build() - } - - override fun onCreateSession(): Session = TalkCarSession() -} - -private class TalkCarSession : Session() { - override fun onCreateScreen(intent: Intent): Screen = TalkCarHomeScreen(carContext) -} - -private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { - override fun onGetTemplate(): Template { - val items = ItemList.Builder() - .addItem( - Row.Builder() - .setTitle("Messages") - .addText("Read, reply to, and start Talk conversations") - .setOnClickListener { - screenManager.push( - TalkCarStatusScreen( - carContext, - "Messages", - "Android Auto messaging notifications and voice replies are enabled. " + - "Conversation history and contact selection are being wired to Talk next." - ) - ) - } - .build() - ) - .addItem( - Row.Builder() - .setTitle("Calls") - .addText("Start and control Talk voice calls") - .setOnClickListener { - screenManager.push( - TalkCarStatusScreen( - carContext, - "Calls", - "Talk is registered with Android Telecom. " + - "The next layer connects Telecom callbacks to Talk WebRTC calls." - ) - ) - } - .build() - ) - .build() - - return ListTemplate.Builder() - .setHeader( - Header.Builder() - .setStartHeaderAction(Action.APP_ICON) - .setTitle("Nextcloud Talk") - .build() - ) - .setSingleList(items) - .build() - } -} - -private class TalkCarStatusScreen( - carContext: CarContext, - private val title: String, - private val status: String -) : Screen(carContext) { - override fun onGetTemplate(): Template = - ListTemplate.Builder() - .setHeader( - Header.Builder() - .setStartHeaderAction(Action.BACK) - .setTitle(title) - .build() - ) - .setSingleList( - ItemList.Builder() - .addItem(Row.Builder().setTitle(status).build()) - .build() - ) - .build() -} -''') - - telecom_file = Path('app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt') - telecom_file.parent.mkdir(parents=True, exist_ok=True) - telecom_file.write_text('''/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2026 Michael Avery - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package com.nextcloud.talk.auto.call - -import android.content.Context -import androidx.core.telecom.CallsManager - -/** - * Owns Talk's Core-Telecom registration for the Android Auto capable build. - * - * Call sessions will be added here as the existing Talk WebRTC lifecycle is - * bridged into Telecom. Registration is intentionally idempotent. - */ -class TalkTelecomManager private constructor(context: Context) { - val callsManager = CallsManager(context.applicationContext) - - @Volatile - private var registered = false - - @Synchronized - fun registerWithTelecom() { - if (registered) return - - val capabilities = - CallsManager.CAPABILITY_BASELINE or CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING - callsManager.registerAppWithTelecom(capabilities) - registered = true - } - - companion object { - @Volatile - private var instance: TalkTelecomManager? = null - - fun get(context: Context): TalkTelecomManager = - instance ?: synchronized(this) { - instance ?: TalkTelecomManager(context).also { instance = it } - } - } -} -''') - PY - - - name: Compile Google Play Android Auto sources - run: ./gradlew :app:compileGplayDebugKotlin --stacktrace - - - name: Commit bootstrap - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/build.gradle.kts app/src/gplay - if git diff --cached --quiet; then - echo "Bootstrap is already present." - exit 0 - fi - git commit -m "feat(auto): add Car App and Telecom foundation" - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-build.yml b/.github/workflows/android-auto-build.yml new file mode 100644 index 00000000000..ce9c68bf8db --- /dev/null +++ b/.github/workflows/android-auto-build.yml @@ -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 diff --git a/.github/workflows/android-auto-fix-verification.yml b/.github/workflows/android-auto-fix-verification.yml deleted file mode 100644 index 2cda7341fc4..00000000000 --- a/.github/workflows/android-auto-fix-verification.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Android Auto - fix dependency verification - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-fix-verification.yml - -permissions: - contents: write - -jobs: - fix-verification: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Trust Google's AndroidX Car signing key for Car App artifacts - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - from pathlib import Path - - p = Path('gradle/verification-metadata.xml') - text = p.read_text() - key = '' - car = ' ' - if car not in text: - if key not in text: - raise SystemExit('Expected Google AndroidX trusted key was not found') - text = text.replace(key, key + '\n' + car, 1) - p.write_text(text) - PY - - - name: Record checksums for newly resolved transitive metadata - shell: bash - run: | - # --write-verification-metadata is allowed to discover and write the exact - # SHA-256 entries required by this classpath. Commit whatever it writes even - # if dependency reporting itself returns non-zero. - set +e - ./gradlew :app:dependencies \ - --configuration gplayDebugCompileClasspath \ - --write-verification-metadata sha256 \ - --stacktrace - echo "Gradle dependency resolution exit code: $?" - exit 0 - - - name: Commit verification update - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add gradle/verification-metadata.xml - if git diff --cached --quiet; then - echo "Verification metadata already complete." - exit 0 - fi - git commit -m "build(auto): verify AndroidX Car dependencies" - git fetch origin android-auto - git rebase origin/android-auto - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-import-pr6012.yml b/.github/workflows/android-auto-import-pr6012.yml deleted file mode 100644 index 55f6445c3fa..00000000000 --- a/.github/workflows/android-auto-import-pr6012.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Android Auto - import upstream messaging support - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-import-pr6012.yml - -permissions: - contents: write - -jobs: - import-pr6012: - runs-on: ubuntu-latest - steps: - - name: Check out Android Auto branch - uses: actions/checkout@v6 - with: - fetch-depth: 0 - ref: android-auto - - - name: Import nextcloud/talk-android PR 6012 as a three-way patch - shell: bash - run: | - set -euo pipefail - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - # The fork shares Git objects with upstream, and this branch was created - # directly from the upstream PR head so the exact source is preserved. - git fetch origin upstream-pr-6012:refs/remotes/origin/upstream-pr-6012 - - PR_BASE="b846aa4fc6467b24bad60e7f347b708dcad793e9" - PR_HEAD="origin/upstream-pr-6012" - - git diff --binary "$PR_BASE".."$PR_HEAD" -- \ - SETUP.md \ - app/src/main/AndroidManifest.xml \ - app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ - app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt \ - app/src/main/res/xml/automotive_app_desc.xml \ - > /tmp/pr6012.patch - - if ! git apply --3way --index /tmp/pr6012.patch; then - echo "::error::PR 6012 still has unresolved three-way conflicts. No changes will be pushed." - git status --short - exit 1 - fi - - if git diff --cached --quiet; then - echo "PR 6012 changes are already present; nothing to commit." - exit 0 - fi - - git commit -m "feat(auto): import upstream Android Auto messaging support" - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-update-verification.yml b/.github/workflows/android-auto-update-verification.yml deleted file mode 100644 index d715490fc26..00000000000 --- a/.github/workflows/android-auto-update-verification.yml +++ /dev/null @@ -1,46 +0,0 @@ -name: Android Auto - update dependency verification - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-update-verification.yml - -permissions: - contents: write - -jobs: - verification: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Generate verification metadata for Android Auto dependencies - shell: bash - run: | - set -euo pipefail - # Resolve the GPlay compile classpath without compiling sources. This lets - # Gradle write the new trusted signatures/checksums even if source code - # still needs a later compile fix. - ./gradlew :app:dependencies \ - --configuration gplayDebugCompileClasspath \ - --write-verification-metadata sha256,pgp \ - --stacktrace - - - name: Commit verification metadata - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add gradle/verification-metadata.xml gradle/verification-keyring.keys 2>/dev/null || true - if git diff --cached --quiet; then - echo "No verification metadata changes were necessary." - exit 0 - fi - git commit -m "build(auto): trust AndroidX Car dependencies" - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-validate-foundation.yml b/.github/workflows/android-auto-validate-foundation.yml deleted file mode 100644 index cd0d7d894f6..00000000000 --- a/.github/workflows/android-auto-validate-foundation.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Android Auto - validate foundation - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-validate-foundation.yml - - app/build.gradle.kts - - app/src/gplay/** - - gradle/verification-metadata.xml - -permissions: - contents: write - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Compile gplay debug Kotlin - id: compile - shell: bash - run: | - set +e - ./gradlew :app:compileGplayDebugKotlin --no-configuration-cache --stacktrace > /tmp/android-auto-build.log 2>&1 - rc=$? - echo "rc=$rc" >> "$GITHUB_OUTPUT" - exit 0 - - - name: Record validation result - shell: bash - run: | - set -euo pipefail - rc='${{ steps.compile.outputs.rc }}' - if [ "$rc" = "0" ]; then - result="PASS" - else - result="FAIL" - fi - { - echo "# Android Auto foundation build" - echo - echo "Result: **$result**" - echo - echo '```text' - tail -n 250 /tmp/android-auto-build.log - echo '```' - } > ANDROID_AUTO_BUILD_STATUS.md - - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add ANDROID_AUTO_BUILD_STATUS.md - if git diff --cached --quiet; then - echo "Validation result is unchanged." - exit 0 - fi - git commit -m "ci(auto): record foundation compile result" - git fetch origin android-auto - git rebase origin/android-auto - git push origin HEAD:android-auto diff --git a/.github/workflows/android-auto-wire-call-bridge.yml b/.github/workflows/android-auto-wire-call-bridge.yml deleted file mode 100644 index 364c82a990a..00000000000 --- a/.github/workflows/android-auto-wire-call-bridge.yml +++ /dev/null @@ -1,142 +0,0 @@ -name: Android Auto - wire Talk call bridge - -on: - push: - branches: - - android-auto - paths: - - .github/workflows/android-auto-wire-call-bridge.yml - -permissions: - contents: write - -jobs: - wire: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto - fetch-depth: 0 - - - name: Patch Talk call lifecycle into Telecom bridge - shell: bash - run: | - python3 - <<'PY' - from pathlib import Path - - def replace_once(text: str, old: str, new: str, label: str) -> str: - count = text.count(old) - if count != 1: - raise SystemExit(f"{label}: expected exactly one match, found {count}") - return text.replace(old, new, 1) - - # NotificationWorker: publish incoming calls to the flavor-neutral bridge. - path = Path('app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt') - text = path.read_text() - if 'import com.nextcloud.talk.call.TalkCallInterop' not in text: - text = replace_once( - text, - 'import com.nextcloud.talk.callnotification.CallNotificationActivity\n', - 'import com.nextcloud.talk.call.TalkCallInterop\n' - 'import com.nextcloud.talk.callnotification.CallNotificationActivity\n', - 'NotificationWorker import' - ) - marker = ''' val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n''' - replacement = ''' val isVideoCall = (conversation.callFlag and Participant.InCallFlags.WITH_VIDEO) > 0\n\n TalkCallInterop.notifyIncomingCall(\n applicationContext,\n bundle,\n conversation.displayName,\n isVideoCall\n )\n\n val primaryAnswerIntent = if (isVideoCall) answerVideoPendingIntent else answerVoicePendingIntent\n''' - if 'TalkCallInterop.notifyIncomingCall(' not in text: - text = replace_once(text, marker, replacement, 'NotificationWorker incoming call hook') - path.write_text(text) - - # CallActivity: register package-local Telecom controls and publish WebRTC lifecycle. - path = Path('app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt') - text = path.read_text() - - if 'import com.nextcloud.talk.call.TalkCallInterop' not in text: - text = replace_once( - text, - 'import com.nextcloud.talk.call.ReactionAnimator\n', - 'import com.nextcloud.talk.call.ReactionAnimator\n' - 'import com.nextcloud.talk.call.TalkCallInterop\n', - 'CallActivity TalkCallInterop import' - ) - if 'import com.nextcloud.talk.utils.registerBroadcastReceiver' not in text: - text = replace_once( - text, - 'import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n', - 'import com.nextcloud.talk.utils.registerBroadcastReceiver\n' - 'import com.nextcloud.talk.utils.registerPermissionHandlerBroadcastReceiver\n', - 'CallActivity registerBroadcastReceiver import' - ) - - field_marker = ''' private var isIncomingCallFromNotification = false\n private val callControlHandler = Handler()\n''' - field_replacement = ''' private var isIncomingCallFromNotification = false\n private var telecomControlReceiverRegistered = false\n private var activeTelecomCallKey: String? = null\n private val telecomControlReceiver = object : BroadcastReceiver() {\n override fun onReceive(context: Context?, intent: Intent?) {\n val action = intent?.action ?: return\n val callKey = intent.getStringExtra(TalkCallInterop.EXTRA_CALL_KEY)\n if (callKey.isNullOrBlank() || callKey != activeTelecomCallKey) return\n\n when (action) {\n TalkCallInterop.ACTION_CONTROL_DISCONNECT -> hangup(shutDownView = true, endCallForAll = false)\n TalkCallInterop.ACTION_CONTROL_MUTE -> {\n val shouldMute = intent.getBooleanExtra(TalkCallInterop.EXTRA_MUTED, false)\n if (microphoneOn == shouldMute) {\n onMicrophoneClick()\n }\n }\n }\n }\n }\n private val callControlHandler = Handler()\n''' - if 'telecomControlReceiverRegistered' not in text: - text = replace_once(text, field_marker, field_replacement, 'CallActivity Telecom receiver fields') - - oncreate_marker = ''' processExtras(intent.extras!!)\n conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n''' - oncreate_replacement = ''' processExtras(intent.extras!!)\n conversationUser = currentUserProviderOld.currentUser.blockingGet()\n\n val telecomAccountId = conversationUser.id\n val telecomRoomToken = roomToken\n if (telecomAccountId != null && !telecomRoomToken.isNullOrBlank()) {\n activeTelecomCallKey = TalkCallInterop.callKey(telecomAccountId, telecomRoomToken)\n registerTelecomControlReceiver()\n TalkCallInterop.notifyCallStarted(\n context = this,\n accountId = telecomAccountId,\n roomToken = telecomRoomToken,\n displayName = conversationName.orEmpty(),\n incoming = isIncomingCallFromNotification,\n video = !isVoiceOnlyCall,\n callExtras = Bundle(extras)\n )\n }\n\n credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)\n''' - if 'TalkCallInterop.notifyCallStarted(' not in text: - text = replace_once(text, oncreate_marker, oncreate_replacement, 'CallActivity start hook') - - helper_marker = ''' private fun initCallRecordingViewModel(recordingState: Int) {\n''' - helper_replacement = ''' private fun registerTelecomControlReceiver() {\n if (telecomControlReceiverRegistered) return\n val filter = IntentFilter().apply {\n addAction(TalkCallInterop.ACTION_CONTROL_DISCONNECT)\n addAction(TalkCallInterop.ACTION_CONTROL_MUTE)\n }\n registerBroadcastReceiver(telecomControlReceiver, filter, ReceiverFlag.NotExported)\n telecomControlReceiverRegistered = true\n }\n\n private fun initCallRecordingViewModel(recordingState: Int) {\n''' - if 'private fun registerTelecomControlReceiver()' not in text: - text = replace_once(text, helper_marker, helper_replacement, 'CallActivity receiver registration helper') - - destroy_marker = ''' CallForegroundService.stop(applicationContext)\n powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n super.onDestroy()\n''' - destroy_replacement = ''' CallForegroundService.stop(applicationContext)\n powerManagerUtils!!.updatePhoneState(PowerManagerUtils.PhoneState.IDLE)\n if (telecomControlReceiverRegistered) {\n unregisterReceiver(telecomControlReceiver)\n telecomControlReceiverRegistered = false\n }\n super.onDestroy()\n''' - if 'unregisterReceiver(telecomControlReceiver)' not in text: - text = replace_once(text, destroy_marker, destroy_replacement, 'CallActivity receiver cleanup') - - hangup_marker = ''' private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n Log.d(TAG, "hangup! shutDownView=$shutDownView")\n joinRoomInitiated = false\n''' - hangup_replacement = ''' private fun hangup(shutDownView: Boolean, endCallForAll: Boolean) {\n Log.d(TAG, "hangup! shutDownView=$shutDownView")\n if (shutDownView && ::conversationUser.isInitialized) {\n val accountId = conversationUser.id\n val token = roomToken\n if (accountId != null && !token.isNullOrBlank()) {\n TalkCallInterop.notifyCallEnded(this, accountId, token)\n }\n }\n joinRoomInitiated = false\n''' - if 'TalkCallInterop.notifyCallEnded(this, accountId, token)' not in text: - text = replace_once(text, hangup_marker, hangup_replacement, 'CallActivity end hook') - - state_marker = ''' if (currentCallStatus == null || currentCallStatus !== callState) {\n currentCallStatus = callState\n if (handler == null) {\n''' - state_replacement = ''' if (currentCallStatus == null || currentCallStatus !== callState) {\n currentCallStatus = callState\n if (\n ::conversationUser.isInitialized &&\n (callState === CallStatus.JOINED || callState === CallStatus.IN_CONVERSATION)\n ) {\n val accountId = conversationUser.id\n val token = roomToken\n if (accountId != null && !token.isNullOrBlank()) {\n TalkCallInterop.notifyCallActive(this, accountId, token)\n }\n }\n if (handler == null) {\n''' - if 'TalkCallInterop.notifyCallActive(this, accountId, token)' not in text: - text = replace_once(text, state_marker, state_replacement, 'CallActivity active hook') - - path.write_text(text) - PY - - - name: Commit call bridge wiring - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt \ - app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt - git commit -m "feat(auto): wire Talk call lifecycle to Telecom" - - - name: Compile gplay debug Kotlin - id: compile - shell: bash - run: | - set +e - ./gradlew :app:compileGplayDebugKotlin --stacktrace > /tmp/android-auto-call-build.log 2>&1 - rc=$? - echo "rc=$rc" >> "$GITHUB_OUTPUT" - exit 0 - - - name: Record build result and push - shell: bash - run: | - set -euo pipefail - rc='${{ steps.compile.outputs.rc }}' - if [ "$rc" = "0" ]; then result="PASS"; else result="FAIL"; fi - { - echo "# Android Auto call bridge build" - echo - echo "Result: **$result**" - echo - echo '```text' - tail -n 240 /tmp/android-auto-call-build.log - echo '```' - } > ANDROID_AUTO_CALL_BUILD_STATUS.md - git add ANDROID_AUTO_CALL_BUILD_STATUS.md - git commit -m "ci(auto): record call bridge compile result" - git push origin HEAD:android-auto diff --git a/ANDROID_AUTO_BUILD_STATUS.md b/ANDROID_AUTO_BUILD_STATUS.md deleted file mode 100644 index ca6bd247175..00000000000 --- a/ANDROID_AUTO_BUILD_STATUS.md +++ /dev/null @@ -1,202 +0,0 @@ -# Android Auto foundation build - -Result: **FAIL** - -```text -Fetching distribution. -Downloading https://services.gradle.org/distributions/gradle-9.7.1-bin.zip -..............10%..............20%...............30%..............40%...............50%..............60%...............70%..............80%..............90%...............100% - -Welcome to Gradle 9.7.1! - -Here are the highlights of this release: - - Isolated Projects graduates to incubating - - Broader Configuration Cache compatibility - - Resilient Sync helps you fix broken builds - - More source locations in problem reports - -For more details see https://docs.gradle.org/9.7.1/release-notes.html - -Starting a Gradle Daemon (subsequent builds will be faster) -Configuration on demand is an incubating feature. - -> Configure project :app -WARNING: The option setting 'android.newDsl=false' is deprecated. -The current default is 'true'. -It will be removed in version 10.0 of the Android Gradle plugin. -Add android.sync.suppressAgpWarnings=UNSUPPORTED_PROJECT_OPTION_USE to the gradle.properties file to suppress this warning. -WARNING: The option setting 'android.enableJetifier=true' is deprecated. -The current default is 'false'. -It will be removed in version 10.0 of the Android Gradle plugin. -Add android.sync.suppressAgpWarnings=UNSUPPORTED_PROJECT_OPTION_USE to the gradle.properties file to suppress this warning. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:25:42: 'fun ExtraPropertiesExtension.provideDelegate(receiver: Any?, property: KProperty<*>): MutablePropertyDelegate' is deprecated. Use 'val property = extra[name] as Type' instead. See the Gradle 9.6 upgrading guide. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:45:1: 'fun Project.android(configure: Action): Unit' is deprecated. Replaced by com.android.build.api.dsl.ApplicationExtension. -This class is not used for the public extensions in AGP when android.newDsl=true, which is the default in AGP 9.0, and will be removed in AGP 10.0. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:102:41: 'fun srcDir(srcDir: Any): Any' is deprecated. Use `directories` mutable set instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:161:9: 'var htmlOutput: File?' is deprecated. Use SingleArtifact.LINT_HTML_REPORT or SingleArtifact.AGGREGATED_LINT_HTML_REPORT to cconsume lint report artifacts. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/build.gradle.kts:162:9: 'var htmlReport: Boolean' is deprecated. Lint reports are now always generated. Use SingleArtifact.LINT_HTML_REPORT or SingleArtifact.AGGREGATED_LINT_HTML_REPORT to consume lint report artifacts. - -> Task :app:preBuild UP-TO-DATE -> Task :app:preGplayDebugBuild UP-TO-DATE -> Task :app:dataBindingMergeDependencyArtifactsGplayDebug -> Task :app:dataBindingMergeDependencyArtifactsGplayDebug FAILED - -[Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html - -FAILURE: Build failed with an exception. - -* What went wrong: -Execution failed for task ':app:dataBindingMergeDependencyArtifactsGplayDebug' (registered by plugin 'com.android.internal.application'). -> Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. - > Could not find androidx.core:core-telecom:1.1.0-beta01. - Required by: - project ':app' - -* Try: -> Run with --info or --debug option to get more log output. -> Run with --scan to get full insights from a Build Scan (powered by Develocity). -> Get more help at https://help.gradle.org. - -* Exception is: -org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:dataBindingMergeDependencyArtifactsGplayDebug' (registered by plugin 'com.android.internal.application'). - at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:38) - at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77) - at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55) - at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52) - at org.gradle.execution.plan.DefaultNodeExecutor.executeLocalTaskNode(DefaultNodeExecutor.java:55) - at org.gradle.execution.plan.DefaultNodeExecutor.execute(DefaultNodeExecutor.java:34) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:355) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:343) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.lambda$execute$0(DefaultTaskExecutionGraph.java:339) - at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:339) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:328) - at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:459) - at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:376) - at org.gradle.execution.plan.DefaultPlanExecutor.process(DefaultPlanExecutor.java:111) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.executeWithServices(DefaultTaskExecutionGraph.java:146) - at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph.execute(DefaultTaskExecutionGraph.java:131) - at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:35) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:54) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor$ExecuteTasks.call(BuildOperationFiringBuildWorkerExecutor.java:43) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.execution.BuildOperationFiringBuildWorkerExecutor.execute(BuildOperationFiringBuildWorkerExecutor.java:40) - at org.gradle.internal.build.DefaultBuildLifecycleController.lambda$executeTasks$0(DefaultBuildLifecycleController.java:323) - at org.gradle.internal.model.StateTransitionController.doTransition(StateTransitionController.java:324) - at org.gradle.internal.model.StateTransitionController.lambda$tryTransition$0(StateTransitionController.java:235) - at org.gradle.internal.work.DefaultSynchronizer.withLock(DefaultSynchronizer.java:45) - at org.gradle.internal.model.StateTransitionController.tryTransition(StateTransitionController.java:235) - at org.gradle.internal.build.DefaultBuildLifecycleController.executeTasks(DefaultBuildLifecycleController.java:314) - at org.gradle.internal.build.DefaultBuildWorkGraphController$DefaultBuildWorkGraph.runWork(DefaultBuildWorkGraphController.java:220) - at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$runAndReleaseLocks$0(DefaultWorkerLeaseService.java:302) - at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:43) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAndReleaseLocks(DefaultWorkerLeaseService.java:300) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:296) - at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:288) - at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:131) - at org.gradle.composite.internal.DefaultBuildController.doRun(DefaultBuildController.java:182) - at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.lambda$run$0(DefaultBuildController.java:199) - at org.gradle.internal.operations.CurrentBuildOperationRef.with(CurrentBuildOperationRef.java:84) - at org.gradle.composite.internal.DefaultBuildController$BuildOpRunnable.run(DefaultBuildController.java:199) - at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:65) - at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47) -Caused by: org.gradle.api.internal.artifacts.ivyservice.TypedResolveException: Could not resolve all files for configuration ':app:gplayDebugCompileClasspath'. - at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailure(ResolveExceptionMapper.java:73) - at org.gradle.api.internal.artifacts.ResolveExceptionMapper.mapFailures(ResolveExceptionMapper.java:65) - at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$DefaultResolutionHost.consolidateFailures(DefaultConfiguration.java:1801) - at org.gradle.api.internal.artifacts.configurations.ResolutionHost.rethrowFailuresAndReportProblems(ResolutionHost.java:75) - at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.maybeThrowResolutionFailures(ResolutionBackedFileCollection.java:86) - at org.gradle.api.internal.artifacts.configurations.ResolutionBackedFileCollection.visitContents(ResolutionBackedFileCollection.java:76) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) - at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:112) - at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:66) - at org.gradle.api.internal.file.collections.UnpackingVisitor.add(UnpackingVisitor.java:91) - at org.gradle.api.internal.file.DefaultFileCollectionFactory$ResolvingFileCollection.visitChildren(DefaultFileCollectionFactory.java:311) - at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:112) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) - at org.gradle.api.internal.file.CompositeFileCollection.lambda$visitContents$0(CompositeFileCollection.java:112) - at org.gradle.api.internal.tasks.PropertyFileCollection.visitChildren(PropertyFileCollection.java:48) - at org.gradle.api.internal.file.CompositeFileCollection.visitContents(CompositeFileCollection.java:112) - at org.gradle.api.internal.file.AbstractFileCollection.visitStructure(AbstractFileCollection.java:358) - at org.gradle.internal.fingerprint.impl.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:48) - at org.gradle.internal.execution.impl.DefaultInputFingerprinter$InputCollectingVisitor.visitInputFileProperty(DefaultInputFingerprinter.java:151) - at org.gradle.api.internal.tasks.execution.TaskExecution.visitMutableInputs(TaskExecution.java:345) - at org.gradle.internal.execution.impl.DefaultInputFingerprinter.fingerprintInputProperties(DefaultInputFingerprinter.java:77) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.captureExecutionStateWithOutputs(CaptureMutableStateBeforeExecutionStep.java:124) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.lambda$captureExecutionState$0(CaptureMutableStateBeforeExecutionStep.java:94) - at org.gradle.internal.execution.steps.BuildOperationStep$1.call(BuildOperationStep.java:38) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:210) - at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:205) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:67) - at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:167) - at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:60) - at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:54) - at org.gradle.internal.execution.steps.BuildOperationStep.operation(BuildOperationStep.java:35) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.captureExecutionState(CaptureMutableStateBeforeExecutionStep.java:92) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.executeMutable(CaptureMutableStateBeforeExecutionStep.java:73) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:65) - at org.gradle.internal.execution.steps.CaptureMutableStateBeforeExecutionStep.execute(CaptureMutableStateBeforeExecutionStep.java:45) - at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeWithNonEmptySources(SkipEmptyMutableWorkStep.java:210) - at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:85) - at org.gradle.internal.execution.steps.SkipEmptyMutableWorkStep.executeMutable(SkipEmptyMutableWorkStep.java:53) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38) - at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.executeMutable(LoadPreviousExecutionStateStep.java:36) - at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.executeMutable(LoadPreviousExecutionStateStep.java:23) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.HandleStaleOutputsStep.executeMutable(HandleStaleOutputsStep.java:77) - at org.gradle.internal.execution.steps.HandleStaleOutputsStep.executeMutable(HandleStaleOutputsStep.java:43) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.lambda$executeMutable$0(AssignMutableWorkspaceStep.java:34) - at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:305) - at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.executeMutable(AssignMutableWorkspaceStep.java:30) - at org.gradle.internal.execution.steps.AssignMutableWorkspaceStep.executeMutable(AssignMutableWorkspaceStep.java:21) - at org.gradle.internal.execution.steps.MutableStep.execute(MutableStep.java:26) - at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:40) - at org.gradle.internal.execution.steps.ChoosePipelineStep.execute(ChoosePipelineStep.java:23) - at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.lambda$execute$2(ExecuteWorkBuildOperationFiringStep.java:67) - at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:67) - at org.gradle.internal.execution.steps.ExecuteWorkBuildOperationFiringStep.execute(ExecuteWorkBuildOperationFiringStep.java:39) - at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:46) - at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:34) - at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:56) - at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:38) - at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:68) - at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:132) - at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:121) - at org.gradle.api.internal.tasks.execution.ProblemsTaskPathTrackingTaskExecuter.execute(ProblemsTaskPathTrackingTaskExecuter.java:41) - at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51) - at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46) - at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57) - at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:74) - at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36) - ... 54 more -Caused by: org.gradle.internal.resolve.ModuleVersionNotFoundException: Could not find androidx.core:core-telecom:1.1.0-beta01. -Required by: - project ':app' - - -Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. - -You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. - -For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. - -BUILD FAILED in 2m 2s -1 actionable task: 1 executed -``` diff --git a/ANDROID_AUTO_CALL_BUILD_STATUS.md b/ANDROID_AUTO_CALL_BUILD_STATUS.md deleted file mode 100644 index 3f644c333b7..00000000000 --- a/ANDROID_AUTO_CALL_BUILD_STATUS.md +++ /dev/null @@ -1,246 +0,0 @@ -# Android Auto call bridge build - -Result: **PASS** - -```text -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:432:41 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:435:71 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:492:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:497:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:523:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:528:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:740:46 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:745:48 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:759:13 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:760:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:819:38 Unnecessary safe call on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:908:78 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:911:13 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:912:74 Unnecessary non-null assertion (!!) on a non-null receiver of type 'EmojiEditText'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:914:59 Unnecessary safe call on a non-null receiver of type 'EmojiEditText'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:928:50 Elvis operator (?:) always returns the left operand of non-nullable type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:948:56 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:951:46 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:955:56 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:1040:60 Unnecessary non-null assertion (!!) on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/MessageInputFragment.kt:1089:48 Unnecessary safe call on a non-null receiver of type 'ImageButton'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/io/MediaRecorderManager.kt:83:20 'constructor(): MediaRecorder' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:513:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:514:17 'fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow' is deprecated. use getChatMessageEntity. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:546:31 'fun getSerializable(p0: String?): Serializable?' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:546:73 Unchecked cast of 'Serializable?' to 'HashMap'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:797:45 'fun getChatMessageForConversation(internalConversationId: String, messageId: Long): Flow' is deprecated. use getChatMessageEntity. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:904:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/OfflineFirstChatRepository.kt:928:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt:82:9 The corresponding parameter in the supertype 'ChatNetworkDataSource' is named 'apiVersion'. This may cause problems when calling this function with named arguments. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/data/network/RetrofitChatNetwork.kt:97:9 The corresponding parameter in the supertype 'ChatNetworkDataSource' is named 'apiVersion'. This may cause problems when calling this function with named arguments. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:533:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:609:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:980:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1010:29 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1020:14 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1026:22 This declaration needs opt-in. Its usage should be marked with '@kotlinx.coroutines.ExperimentalCoroutinesApi' or '@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)' -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1057:14 This declaration is in a preview state and can be changed in a backwards-incompatible manner with a best-effort migration. Its usage should be marked with '@kotlinx.coroutines.FlowPreview' or '@OptIn(kotlinx.coroutines.FlowPreview::class)' if you accept the drawback of relying on preview API -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1058:23 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1072:46 Elvis operator (?:) always returns the left operand of non-nullable type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1123:14 This declaration is in a preview state and can be changed in a backwards-incompatible manner with a best-effort migration. Its usage should be marked with '@kotlinx.coroutines.FlowPreview' or '@OptIn(kotlinx.coroutines.FlowPreview::class)' if you accept the drawback of relying on preview API -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1154:40 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1527:19 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1529:17 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1538:9 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1560:32 'fun getRoom(user: User, roomToken: String): Job' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1560:40 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1742:62 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1897:20 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1906:22 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1940:17 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1972:51 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1972:73 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1974:23 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:1983:21 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2001:51 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2001:73 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2003:23 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2012:21 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2130:45 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2205:51 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2215:13 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2215:24 Unnecessary safe call on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2221:51 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2353:20 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2357:21 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2358:21 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2366:44 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2367:13 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2377:48 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2378:17 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2389:44 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2390:13 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2401:48 'suspend fun getLocallyStoredConversation(user: User, roomToken: String): ConversationModel?' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2402:17 'var currentUser: User' is deprecated. use currentUserFlow. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2416:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2426:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2434:17 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ChatViewModel.kt:2441:13 'fun getRoom(token: String): Unit' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chat/viewmodels/ScheduledMessagesViewModel.kt:242:28 'suspend fun getParentMessageById(messageId: Long): Flow' is deprecated. getMessage(messageId: Long, bundle: Bundle). -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/ChooseAccountDialogCompose.kt:111:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/viewmodel/StatusMessageViewModel.kt:39:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/chooseaccount/viewmodel/StatusViewModel.kt:25:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/components/ColoredStatusBar.kt:54:25 'var statusBarColor: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/components/StandardAppBar.kt:75:34 Unnecessary safe call on a non-null receiver of type 'List Unit>>'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt:32:62 Java type mismatch: inferred type is 'MutableMap?', but '(Mutable)Map' was expected. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/contacts/ContactsRepositoryImpl.kt:84:66 Java type mismatch: inferred type is 'MutableMap?', but '(Mutable)Map' was expected. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationcreation/viewmodel/ConversationCreationViewModel.kt:31:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationcreation/viewmodel/ConversationCreationViewModel.kt:174:25 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:507:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:665:19 'fun demoteModeratorToUser(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:668:29 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:671:19 'fun promoteUserToModerator(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:674:29 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:706:23 'fun removeParticipantFromConversation(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:708:30 'fun getUrlForRemovingParticipantFromConversation(baseUrl: String?, roomToken: String?, isGuest: Boolean): String' is deprecated. This is only supported on API v1-3, in API v4+ please use {@link ApiUtils#getUrlForAttendees(int, String, String)} instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:709:33 'var sessionId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:712:23 'fun removeParticipantFromConversation(authorization: String!, url: String!, participantId: String!): Observable!' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:714:30 'fun getUrlForRemovingParticipantFromConversation(baseUrl: String?, roomToken: String?, isGuest: Boolean): String' is deprecated. This is only supported on API v1-3, in API v4+ please use {@link ApiUtils#getUrlForAttendees(int, String, String)} instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt:715:33 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/ParticipantItemAdapter.kt:252:35 'fun getColor(p0: Int): Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:330:58 Elvis operator (?:) always returns the left operand of non-nullable type 'Long'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:331:35 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt:355:13 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:202:13 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1221:48 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1221:76 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1236:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt:1481:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:81:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:105:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:114:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/data/network/OfflineFirstConversationsRepository.kt:162:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/ui/ConversationListItem.kt:114:55 'var activeUser: User?' is deprecated. should be deleted in long term. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:74:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:408:49 Unnecessary safe call on a non-null receiver of type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationlist/viewmodels/ConversationsListViewModel.kt:537:30 'fun getRooms(user: User): Job' is deprecated. use observeConversation. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/conversationtags/viewmodels/ConversationTagsViewModel.kt:38:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt:53:98 Unchecked cast of 'ViewModel?' to 'T (of fun create)'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/data/source/local/converters/HashMapHashMapConverter.kt:29:65 Unchecked cast of '(Mutable)Map!>!' to 'HashMap>?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisViewModel.kt:25:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt:139:17 'var activeUser: User?' is deprecated. should be deleted in long term. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/extensions/ImageViewExtensions.kt:140:17 'var activeUser: User?' is deprecated. should be deleted in long term. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/filebrowser/webdav/ReadFolderListingOperation.kt:84:17 Expression is unused. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/invitation/InvitationsActivity.kt:62:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:62:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:467:29 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:487:22 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ContactAddressBookWorker.kt:499:18 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/DownloadFileToCacheWorker.kt:45:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/LeaveConversationWorker.kt:49:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/SaveFileToStorageWorker.kt:53:21 Condition is always 'true'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/ShareOperationWorker.kt:125:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:89:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:557:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt:572:25 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/components/LocationPickerScreen.kt:151:50 Unnecessary non-null assertion (!!) on a non-null receiver of type 'GeocodingResult'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/components/LocationPickerScreen.kt:151:86 Unnecessary non-null assertion (!!) on a non-null receiver of type 'GeocodingResult'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/location/viewmodels/LocationPickerViewModel.kt:37:41 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/lock/LockedActivity.kt:128:39 'fun createConfirmDeviceCredentialIntent(p0: CharSequence!, p1: CharSequence!): Intent!' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchActivity.kt:76:16 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/messagesearch/MessageSearchViewModel.kt:40:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/domain/converters/DomainEnumNotificationLevelConverter.kt:30:13 'when' is exhaustive so 'else' is redundant here. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt:94:17 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/participants/Participant.kt:108:13 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:92:40 Unnecessary safe call on a non-null receiver of type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:96:39 Unnecessary safe call on a non-null receiver of type 'Boolean'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:97:42 Unnecessary safe call on a non-null receiver of type 'Boolean'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:98:47 Unnecessary safe call on a non-null receiver of type 'Boolean'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/models/json/push/DecryptedPushMessage.kt:101:42 Unnecessary safe call on a non-null receiver of type 'Long'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/openconversations/ListOpenConversationsActivity.kt:43:20 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt:38:30 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/ui/PollMainDialogFragment.kt:175:24 'fun bundleOf(vararg pairs: Pair): Bundle' is deprecated. This method does not provide type safety at compile time. Use the platform `Bundle` class directly instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollCreateViewModel.kt:26:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollMainViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/polls/viewmodels/PollVoteViewModel.kt:26:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/profile/ProfileActivity.kt:175:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/raisehand/viewmodel/RaiseHandViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt:53:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/DismissRecordingAvailableReceiver.kt:38:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/MarkAsReadReceiver.kt:40:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/receivers/ShareRecordingToChatReceiver.kt:41:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/activities/RemoteFileBrowserActivity.kt:55:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/repositories/RemoteFileBrowserItemsRepositoryImpl.kt:30:59 Unchecked cast of 'Any!' to 'List'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/remotefilebrowser/viewmodels/RemoteFileBrowserItemsViewModel.kt:52:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:340:23 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:660:13 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt:667:17 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/shareditems/activities/SharedItemsActivity.kt:82:20 'var currentUserProviderOld: CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/shareditems/repositories/SharedItemsRepositoryImpl.kt:106:77 Unnecessary non-null assertion (!!) on a non-null receiver of type 'String'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:323:53 Unchecked cast of 'Any?' to 'Map?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:384:49 Unchecked cast of 'Any?' to 'Map?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:470:40 Unchecked cast of 'Any?' to 'List>?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:517:40 Unchecked cast of 'Map' to 'Map'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:546:21 'var sessionId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/signaling/SignalingMessageReceiver.kt:549:25 'var userId: String?' is deprecated. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/threadsoverview/viewmodels/ThreadsOverviewViewModel.kt:30:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/translate/viewmodels/TranslateViewModel.kt:28:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/chat/MediaMessage.kt:286:69 No cast needed. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/DateTimeCompose.kt:95:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/DialogBanListFragment.kt:44:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:38:39 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:49:79 Unchecked cast of 'HashMap<*, *>?' to 'HashMap'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:51:24 'fun getSerializable(p0: String?): Serializable?' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt:51:58 Unchecked cast of 'Serializable?' to 'HashMap'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/MoreCallActionsDialog.kt:105:61 Unnecessary safe call on a non-null receiver of type 'User'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/dialog/SaveToStorageDialogFragment.kt:105:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/MaterialSchemesProviderImpl.kt:19:31 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:100:20 'static fun setBackground(p0: View, p1: Drawable?): Unit' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:124:24 'static fun setBackground(p0: View, p1: Drawable?): Unit' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/ui/theme/TalkSpecificViewThemeUtils.kt:434:59 'var activeUser: User?' is deprecated. should be deleted in long term. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/upload/chunked/ChunkedFileUploader.kt:141:17 Expression is unused. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt:129:25 'fun create(contentType: MediaType?, content: ByteArray, offset: Int = ..., byteCount: Int = ...): RequestBody' is deprecated. Moved to extension function. Put the 'content' argument first to fix Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:104:29 'field versionCode: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:105:91 'static field GET_SIGNATURES: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:105:107 'field signatures: Array<(out) Signature!>?' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:108:36 'static field GET_SIGNATURES: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt:109:19 'field signatures: Array<(out) Signature!>?' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:152:25 'fun getColor(p0: Int): Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:313:26 'static field SYSTEM_UI_FLAG_LIGHT_STATUS_BAR: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:314:30 'static field SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:316:23 'var systemUiVisibility: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:318:23 'var systemUiVisibility: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:320:20 'var statusBarColor: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/DisplayUtils.kt:346:16 'var navigationBarColor: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt:322:21 'fun getInstance(): WorkManager' is deprecated. Use the overload receiving Context. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/FileViewerUtils.kt:325:36 The corresponding parameter in the supertype 'Observer' is named 'value'. This may cause problems when calling this function with named arguments. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/ImageEmojiEditText.kt:60:38 'static fun createWrapper(p0: InputConnection, p1: EditorInfo, p2: InputConnectionCompat.OnCommitContentListener): InputConnection' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt:101:43 'static field USAGE_NOTIFICATION_COMMUNICATION_REQUEST: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/NotificationUtils.kt:122:43 'static field USAGE_NOTIFICATION_COMMUNICATION_INSTANT: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt:81:21 'fun tryPickDistributor(context: Context, callback: (Boolean) -> Unit): Unit' is deprecated. Use tryPickDistributor(activity, callback) instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/VibrationUtils.kt:17:57 'static field VIBRATOR_SERVICE: String' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/CurrentUserProviderOldImpl.kt:22:94 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/UserModule.kt:23:37 'class CurrentUserProviderOldImpl : CurrentUserProviderOld' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/database/user/UserModule.kt:24:8 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:45:26 'static field SCREEN_BRIGHT_WAKE_LOCK: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:45:66 'static field ACQUIRE_CAUSES_WAKEUP: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:55:50 'static field WIFI_MODE_FULL_HIGH_PERF: Int' is deprecated. Deprecated in Java. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/power/PowerManagerUtils.kt:152:13 'when' is exhaustive so 'else' is redundant here. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtils.kt:96:23 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtils.kt:97:17 'constructor(userManager: UserManager): CurrentUserProviderOldImpl' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:62:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:72:26 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/utils/preview/ComposePreviewUtilsDaos.kt:74:18 This declaration overrides a deprecated member but is not marked as deprecated itself. Add the '@Deprecated' annotation or suppress the diagnostic. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/viewmodels/CallRecordingViewModel.kt:27:38 'interface CurrentUserProviderOld : Any' is deprecated. Use CurrentUserProvider instead. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:255:80 Unchecked cast of 'Any?' to 'List>?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:260:51 Unchecked cast of 'Any?' to 'HashMap?'. -w: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/app/src/main/java/com/nextcloud/talk/webrtc/WebSocketInstance.kt:279:82 Unchecked cast of 'Any?' to 'List?'. - -[Incubating] Problems report is available at: file:///home/runner/work/Nextcloud_Talk_Android_Auto/Nextcloud_Talk_Android_Auto/build/reports/problems/problems-report.html - -Deprecated Gradle features were used in this build, making it incompatible with Gradle 10. - -You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. - -For more on this, please refer to https://docs.gradle.org/9.7.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. - -BUILD SUCCESSFUL in 6m 27s -13 actionable tasks: 13 executed -Configuration cache entry stored. -``` From ddbbe5f901a6db4fa0851d96e96cd5a6c1f2bcd1 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:32:22 -0400 Subject: [PATCH 43/73] feat(auto): expose Telecom audio endpoint state --- .../nextcloud/talk/call/TalkCallInterop.kt | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt index 4f1910765a7..a131f075b4b 100644 --- a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt +++ b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt @@ -27,6 +27,14 @@ object TalkCallInterop { const val ACTION_CONTROL_DISCONNECT = "com.nextcloud.talk.call.action.CONTROL_DISCONNECT" const val ACTION_CONTROL_MUTE = "com.nextcloud.talk.call.action.CONTROL_MUTE" + const val ACTION_CONTROL_AUDIO_ENDPOINT = "com.nextcloud.talk.call.action.CONTROL_AUDIO_ENDPOINT" + const val ACTION_TELECOM_AUDIO_STATE_CHANGED = "com.nextcloud.talk.call.action.TELECOM_AUDIO_STATE_CHANGED" + + const val AUDIO_ROUTE_EARPIECE = "earpiece" + const val AUDIO_ROUTE_BLUETOOTH = "bluetooth" + const val AUDIO_ROUTE_WIRED_HEADSET = "wired_headset" + const val AUDIO_ROUTE_SPEAKER = "speaker" + const val AUDIO_ROUTE_EXTERNAL = "external" const val EXTRA_CALL_KEY = "talk_call_key" const val EXTRA_CALL_EXTRAS = "talk_call_extras" @@ -34,6 +42,16 @@ object TalkCallInterop { const val EXTRA_INCOMING = "talk_incoming" const val EXTRA_VIDEO = "talk_video" const val EXTRA_MUTED = "talk_muted" + const val EXTRA_AUDIO_ROUTE = "talk_audio_route" + + @Volatile + private var activeTelecomCallKey: String? = null + + @Volatile + private var telecomCurrentAudioRoute: String? = null + + @Volatile + private var telecomAvailableAudioRoutes: Array = emptyArray() fun callKey(accountId: Long, roomToken: String): String = "$accountId@$roomToken" @@ -100,6 +118,55 @@ object TalkCallInterop { ) } + @JvmStatic + fun requestTelecomAudioRoute(context: Context, route: String) { + val callKey = activeTelecomCallKey ?: return + send( + context, + Intent(ACTION_CONTROL_AUDIO_ENDPOINT) + .putExtra(EXTRA_CALL_KEY, callKey) + .putExtra(EXTRA_AUDIO_ROUTE, route) + ) + } + + fun beginTelecomAudioManagement(context: Context, callKey: String) { + if (callKey.isBlank()) return + activeTelecomCallKey = callKey + telecomCurrentAudioRoute = null + telecomAvailableAudioRoutes = emptyArray() + send(context, Intent(ACTION_TELECOM_AUDIO_STATE_CHANGED).putExtra(EXTRA_CALL_KEY, callKey)) + } + + fun updateTelecomAudioState( + context: Context, + callKey: String, + currentRoute: String?, + availableRoutes: Array + ) { + if (callKey.isBlank()) return + activeTelecomCallKey = callKey + telecomCurrentAudioRoute = currentRoute + telecomAvailableAudioRoutes = availableRoutes.copyOf() + send(context, Intent(ACTION_TELECOM_AUDIO_STATE_CHANGED).putExtra(EXTRA_CALL_KEY, callKey)) + } + + fun clearTelecomAudioState(context: Context, callKey: String) { + if (callKey.isBlank() || activeTelecomCallKey != callKey) return + activeTelecomCallKey = null + telecomCurrentAudioRoute = null + telecomAvailableAudioRoutes = emptyArray() + send(context, Intent(ACTION_TELECOM_AUDIO_STATE_CHANGED).putExtra(EXTRA_CALL_KEY, callKey)) + } + + @JvmStatic + fun isTelecomAudioManaged(): Boolean = activeTelecomCallKey != null + + @JvmStatic + fun getTelecomCurrentAudioRoute(): String? = telecomCurrentAudioRoute + + @JvmStatic + fun getTelecomAvailableAudioRoutes(): Array = telecomAvailableAudioRoutes.copyOf() + private fun notifySimple(context: Context, action: String, accountId: Long, roomToken: String) { if (accountId < 0L || roomToken.isBlank()) return send(context, Intent(action).putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken))) From 4e100fb3adaf8093d7d1df98099b3a2d285bac63 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:32:45 -0400 Subject: [PATCH 44/73] feat(auto): route audio endpoint requests to Telecom --- .../talk/auto/call/TalkTelecomInteropReceiver.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt index d8f2d778fd0..a270ea55a11 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt @@ -20,6 +20,7 @@ class TalkTelecomInteropReceiver : BroadcastReceiver() { when (intent.action) { TalkCallInterop.ACTION_INCOMING_CALL -> { + TalkCallInterop.beginTelecomAudioManagement(context, callKey) manager.onIncomingCall( callKey = callKey, callExtras = intent.getBundleExtra(TalkCallInterop.EXTRA_CALL_EXTRAS) ?: Bundle(), @@ -29,6 +30,7 @@ class TalkTelecomInteropReceiver : BroadcastReceiver() { } TalkCallInterop.ACTION_CALL_STARTED -> { + TalkCallInterop.beginTelecomAudioManagement(context, callKey) manager.onCallStarted( callKey = callKey, callExtras = intent.getBundleExtra(TalkCallInterop.EXTRA_CALL_EXTRAS) ?: Bundle(), @@ -40,6 +42,12 @@ class TalkTelecomInteropReceiver : BroadcastReceiver() { TalkCallInterop.ACTION_CALL_ACTIVE -> manager.onCallActive(callKey) TalkCallInterop.ACTION_CALL_ENDED -> manager.onCallEnded(callKey) + TalkCallInterop.ACTION_CONTROL_AUDIO_ENDPOINT -> { + manager.requestAudioEndpoint( + callKey, + intent.getStringExtra(TalkCallInterop.EXTRA_AUDIO_ROUTE).orEmpty() + ) + } } } } From bb510b50925a34aea082447a965959ac20ee9743 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:33:35 -0400 Subject: [PATCH 45/73] feat(auto): mirror and request Telecom audio endpoints --- .../talk/auto/call/TalkTelecomManager.kt | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index 2647ee8242b..0a1fb62f295 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -15,6 +15,7 @@ import android.util.Log import androidx.core.app.NotificationManagerCompat import androidx.core.telecom.CallAttributesCompat import androidx.core.telecom.CallControlScope +import androidx.core.telecom.CallEndpointCompat import androidx.core.telecom.CallsManager import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.call.TalkCallInterop @@ -109,6 +110,7 @@ class TalkTelecomManager private constructor(context: Context) { } fun onCallEnded(callKey: String) { + TalkCallInterop.clearTelecomAudioState(appContext, callKey) val managed = calls.remove(callKey) ?: return managed.control?.let { control -> scope.launch { @@ -119,6 +121,26 @@ class TalkTelecomManager private constructor(context: Context) { } } + fun requestAudioEndpoint(callKey: String, route: String) { + if (callKey.isBlank() || route.isBlank()) return + val managed = calls[callKey] ?: return + val control = managed.control ?: return + val endpoint = managed.availableEndpoints.firstOrNull { endpoint -> + routeForEndpoint(endpoint) == route + } ?: run { + Log.w(TAG, "No Telecom endpoint for requested route $route on $callKey") + return + } + + scope.launch { + runCatching { + control.requestEndpointChange(endpoint) + }.onFailure { + Log.w(TAG, "Unable to request Telecom audio route $route for $callKey", it) + } + } + } + private suspend fun activateStartedCall(managed: ManagedCall, control: CallControlScope) { runCatching { when { @@ -196,6 +218,7 @@ class TalkTelecomManager private constructor(context: Context) { TalkCallInterop.requestDisconnect(appContext, managed.callKey) } else { calls.remove(managed.callKey) + TalkCallInterop.clearTelecomAudioState(appContext, managed.callKey) } }, onSetActive = { @@ -212,12 +235,31 @@ class TalkTelecomManager private constructor(context: Context) { TalkCallInterop.requestDisconnect(appContext, managed.callKey) } else { calls.remove(managed.callKey) + TalkCallInterop.clearTelecomAudioState(appContext, managed.callKey) } } ) { val callControl = this managed.control = callControl + scope.launch { + currentCallEndpoint + .distinctUntilChanged() + .collect { endpoint -> + managed.currentEndpoint = endpoint + publishAudioState(managed) + } + } + + scope.launch { + availableEndpoints + .distinctUntilChanged() + .collect { endpoints -> + managed.availableEndpoints = endpoints + publishAudioState(managed) + } + } + scope.launch { isMuted .distinctUntilChanged() @@ -232,11 +274,37 @@ class TalkTelecomManager private constructor(context: Context) { } } catch (t: Throwable) { calls.remove(callKey) + TalkCallInterop.clearTelecomAudioState(appContext, callKey) Log.e(TAG, "Unable to add Talk call to Telecom: $callKey", t) } } } + private fun publishAudioState(managed: ManagedCall) { + val currentRoute = managed.currentEndpoint?.let(::routeForEndpoint) + val availableRoutes = managed.availableEndpoints + .mapNotNull(::routeForEndpoint) + .distinct() + .toTypedArray() + + TalkCallInterop.updateTelecomAudioState( + appContext, + managed.callKey, + currentRoute, + availableRoutes + ) + } + + private fun routeForEndpoint(endpoint: CallEndpointCompat): String? = + when (endpoint.type) { + CallEndpointCompat.TYPE_EARPIECE -> TalkCallInterop.AUDIO_ROUTE_EARPIECE + CallEndpointCompat.TYPE_BLUETOOTH -> TalkCallInterop.AUDIO_ROUTE_BLUETOOTH + CallEndpointCompat.TYPE_WIRED_HEADSET -> TalkCallInterop.AUDIO_ROUTE_WIRED_HEADSET + CallEndpointCompat.TYPE_SPEAKER -> TalkCallInterop.AUDIO_ROUTE_SPEAKER + CallEndpointCompat.TYPE_STREAMING -> TalkCallInterop.AUDIO_ROUTE_EXTERNAL + else -> null + } + private fun launchTalkCall(managed: ManagedCall, voiceOnly: Boolean) { managed.activityStarted = true cancelIncomingNotification(managed) @@ -267,7 +335,9 @@ class TalkTelecomManager private constructor(context: Context) { val video: Boolean, @Volatile var activityStarted: Boolean, @Volatile var answeredByTelecom: Boolean = false, - @Volatile var control: CallControlScope? = null + @Volatile var control: CallControlScope? = null, + @Volatile var currentEndpoint: CallEndpointCompat? = null, + @Volatile var availableEndpoints: List = emptyList() ) companion object { From e842c8bc5592335d1ea21a8c6e8f093c800424d4 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:34:02 -0400 Subject: [PATCH 46/73] feat(auto): receive Telecom audio route requests --- app/src/gplay/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 33b8472cfc4..68e13871e43 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -55,6 +55,7 @@ + From cd3ad782a8d5c54374449968bb71a1959b5f3f02 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:35:38 -0400 Subject: [PATCH 47/73] feat(auto): delegate Talk call audio routing to Telecom --- .../talk/webrtc/WebRtcAudioManager.java | 191 ++++++++++++++++-- 1 file changed, 173 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java index aec2561da77..948a3ef1ccb 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/WebRtcAudioManager.java @@ -30,6 +30,7 @@ import android.media.AudioManager; import android.util.Log; +import com.nextcloud.talk.call.TalkCallInterop; import com.nextcloud.talk.events.ProximitySensorEvent; import com.nextcloud.talk.utils.ContextExtensionsKt; import com.nextcloud.talk.utils.ReceiverFlag; @@ -54,6 +55,9 @@ public class WebRtcAudioManager { private boolean savedIsSpeakerPhoneOn = false; private boolean savedIsMicrophoneMute = false; private boolean hasWiredHeadset = false; + private boolean telecomManagedAudioSession = false; + private boolean wiredHeadsetReceiverRegistered = false; + private boolean telecomAudioStateReceiverRegistered = false; private AudioDevice userSelectedAudioDevice; private AudioDevice currentAudioDevice; @@ -66,6 +70,7 @@ public class WebRtcAudioManager { private Set internalAudioDevices = new HashSet<>(); private final BroadcastReceiver wiredHeadsetReceiver; + private final BroadcastReceiver telecomAudioStateReceiver; private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener; private AudioFocusRequest audioFocusRequest; private final AudioFocusState audioFocusState = new AudioFocusState(); @@ -79,6 +84,14 @@ private WebRtcAudioManager(Context context, boolean useProximitySensor) { audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)); bluetoothManager = WebRtcBluetoothManager.create(context, this); wiredHeadsetReceiver = new WiredHeadsetReceiver(); + telecomAudioStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (TalkCallInterop.ACTION_TELECOM_AUDIO_STATE_CHANGED.equals(intent.getAction())) { + updateAudioDeviceState(); + } + } + }; amState = AudioManagerState.UNINITIALIZED; powerManagerUtils = new PowerManagerUtils(); @@ -108,6 +121,10 @@ public static WebRtcAudioManager create(Context context, boolean useProximitySen } public void startBluetoothManager() { + if (isTelecomAudioManaged()) { + Log.d(TAG, "Telecom owns audio routing; not starting the legacy Bluetooth SCO manager"); + return; + } // Initialize and start Bluetooth if a BT device is available or initiate // detection of new (enabled) BT devices. bluetoothManager.start(); @@ -118,7 +135,7 @@ public void startBluetoothManager() { * NEAR". */ private void onProximitySensorChangedState() { - if (!useProximitySensor) { + if (!useProximitySensor || isTelecomAudioManaged()) { return; } @@ -154,6 +171,7 @@ public void start(AudioManagerListener audioManagerListener) { Log.d(TAG, "AudioManager starts..."); this.audioManagerListener = audioManagerListener; amState = AudioManagerState.RUNNING; + telecomManagedAudioSession = TalkCallInterop.isTelecomAudioManaged(); // Store current audio state so we can restore it when stop() is called. savedAudioMode = audioManager.getMode(); @@ -174,11 +192,14 @@ public void start(AudioManagerListener audioManagerListener) { // Start by setting MODE_IN_COMMUNICATION as default audio mode. It is // required to be in this mode when playout and/or recording starts for - // best possible VoIP performance. + // best possible VoIP performance. Telecom owns the endpoint, not this mode. audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION); - // Always disable microphone mute during a WebRTC call. - setMicrophoneMute(false); + // Legacy calls use AudioManager mute state. Telecom-managed calls mirror + // mute through the WebRTC track instead, so don't override Telecom here. + if (!telecomManagedAudioSession) { + setMicrophoneMute(false); + } // Set initial device states. userSelectedAudioDevice = AudioDevice.NONE; @@ -187,17 +208,22 @@ public void start(AudioManagerListener audioManagerListener) { audioDevices.clear(); internalAudioDevices.clear(); - startBluetoothManager(); + registerReceiver( + telecomAudioStateReceiver, + new IntentFilter(TalkCallInterop.ACTION_TELECOM_AUDIO_STATE_CHANGED) + ); + telecomAudioStateReceiverRegistered = true; + + if (!telecomManagedAudioSession) { + startBluetoothManager(); + proximitySensor.start(); + registerReceiver(wiredHeadsetReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); + wiredHeadsetReceiverRegistered = true; + } - // Do initial selection of audio device. This setting can later be changed - // either by adding/removing a BT or wired headset or by covering/uncovering - // the proximity sensor. + // Do initial selection of audio device. In a Telecom-managed call this + // consumes Telecom's endpoint flows; otherwise it uses Talk's legacy route logic. updateAudioDeviceState(); - - proximitySensor.start(); - // Register receiver for broadcast intents related to adding/removing a - // wired headset. - registerReceiver(wiredHeadsetReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); Log.d(TAG, "AudioManager started"); } @@ -263,15 +289,25 @@ public void stop() { } amState = AudioManagerState.UNINITIALIZED; - unregisterReceiver(wiredHeadsetReceiver); + if (wiredHeadsetReceiverRegistered) { + unregisterReceiver(wiredHeadsetReceiver); + wiredHeadsetReceiverRegistered = false; + } + if (telecomAudioStateReceiverRegistered) { + unregisterReceiver(telecomAudioStateReceiver); + telecomAudioStateReceiverRegistered = false; + } if(bluetoothManager.started()) { bluetoothManager.stop(); } - // Restore previously stored audio states. - setSpeakerphoneOn(savedIsSpeakerPhoneOn); - setMicrophoneMute(savedIsMicrophoneMute); + // Don't alter endpoint or global microphone state for a Telecom-managed + // session. Telecom restores the route after the call leaves its scope. + if (!telecomManagedAudioSession) { + setSpeakerphoneOn(savedIsSpeakerPhoneOn); + setMicrophoneMute(savedIsMicrophoneMute); + } audioManager.setMode(savedAudioMode); // Abandon audio focus. Gives the previous focus owner, if any, focus. @@ -290,6 +326,7 @@ public void stop() { powerManagerUtils.updatePhoneState(PowerManagerUtils.PhoneState.IDLE); audioManagerListener = null; + telecomManagedAudioSession = false; Log.d(TAG, "AudioManager stopped"); } @@ -301,6 +338,11 @@ public void stop() { private void setAudioDeviceInternal(AudioDevice audioDevice) { Log.d(TAG, "setAudioDeviceInternal(device=" + audioDevice + ")"); + if (isTelecomAudioManaged()) { + // Telecom endpoint changes arrive asynchronously through currentCallEndpoint. + return; + } + if (audioDevices.contains(audioDevice)) { switch (audioDevice) { case SPEAKER_PHONE: @@ -324,10 +366,13 @@ private void setAudioDeviceInternal(AudioDevice audioDevice) { */ public void setDefaultAudioDevice(AudioDevice device) { ThreadUtils.checkIsOnMainThread(); + defaultAudioDevice = device; + if (isTelecomAudioManaged()) { + return; + } if (!audioDevices.contains(device)) { Log.e(TAG, "Can not select default " + device + " from available " + audioDevices); } - defaultAudioDevice = device; updateAudioDeviceState(); } @@ -336,6 +381,14 @@ public void setDefaultAudioDevice(AudioDevice device) { */ public void selectAudioDevice(AudioDevice device) { ThreadUtils.checkIsOnMainThread(); + if (isTelecomAudioManaged()) { + String route = toTelecomAudioRoute(device); + if (route != null) { + userSelectedAudioDevice = device; + TalkCallInterop.requestTelecomAudioRoute(context, route); + } + return; + } if (!audioDevices.contains(device)) { Log.e(TAG, "Can not select " + device + " from available " + audioDevices); } @@ -377,6 +430,10 @@ private void unregisterReceiver(BroadcastReceiver receiver) { * Sets the speaker phone mode. */ private void setSpeakerphoneOn(boolean on) { + if (isTelecomAudioManaged()) { + Log.d(TAG, "Telecom owns speaker routing; ignoring setSpeakerphoneOn(" + on + ")"); + return; + } boolean wasOn = audioManager.isSpeakerphoneOn(); if (wasOn == on) { return; @@ -388,6 +445,9 @@ private void setSpeakerphoneOn(boolean on) { * Sets the microphone mute state. */ private void setMicrophoneMute(boolean on) { + if (isTelecomAudioManaged()) { + return; + } boolean wasMuted = audioManager.isMicrophoneMute(); if (wasMuted == on) { return; @@ -425,6 +485,15 @@ private boolean hasWiredHeadset() { public final void updateAudioDeviceState() { ThreadUtils.checkIsOnMainThread(); + + if (TalkCallInterop.isTelecomAudioManaged()) { + telecomManagedAudioSession = true; + } + if (telecomManagedAudioSession) { + updateTelecomAudioDeviceState(); + return; + } + Log.d(TAG, "--- updateAudioDeviceState: " + "wired headset=" + hasWiredHeadset + ", " + "BT state=" + bluetoothManager.getState()); @@ -557,6 +626,92 @@ public final void updateAudioDeviceState() { Log.d(TAG, "--- updateAudioDeviceState done"); } + private void updateTelecomAudioDeviceState() { + String currentRoute = TalkCallInterop.getTelecomCurrentAudioRoute(); + String[] availableRoutes = TalkCallInterop.getTelecomAvailableAudioRoutes(); + Set newAudioDevices = new HashSet<>(); + + for (String route : availableRoutes) { + AudioDevice device = fromTelecomAudioRoute(route); + if (device != AudioDevice.NONE) { + newAudioDevices.add(device); + } + } + + AudioDevice newCurrentAudioDevice = fromTelecomAudioRoute(currentRoute); + if (newCurrentAudioDevice != AudioDevice.NONE) { + newAudioDevices.add(newCurrentAudioDevice); + } + + // beginTelecomAudioManagement() deliberately publishes an empty snapshot + // before Telecom's endpoint flows emit. Keep the last visible state until + // the real snapshot arrives instead of flashing the picker to an empty list. + if (newAudioDevices.isEmpty() && newCurrentAudioDevice == AudioDevice.NONE) { + Log.d(TAG, "Waiting for initial Telecom audio endpoint snapshot"); + return; + } + + boolean audioDeviceSetUpdated = !audioDevices.equals(newAudioDevices); + boolean currentAudioDeviceUpdated = + newCurrentAudioDevice != AudioDevice.NONE && newCurrentAudioDevice != currentAudioDevice; + + internalAudioDevices = new HashSet<>(newAudioDevices); + audioDevices = new HashSet<>(newAudioDevices); + if (newCurrentAudioDevice != AudioDevice.NONE) { + currentAudioDevice = newCurrentAudioDevice; + } + + Log.d(TAG, "Telecom audio state: available=" + audioDevices + ", current=" + currentAudioDevice); + if ((audioDeviceSetUpdated || currentAudioDeviceUpdated) && audioManagerListener != null) { + audioManagerListener.onAudioDeviceChanged(currentAudioDevice, audioDevices); + } + } + + private boolean isTelecomAudioManaged() { + return telecomManagedAudioSession || TalkCallInterop.isTelecomAudioManaged(); + } + + private static String toTelecomAudioRoute(AudioDevice device) { + if (device == null) { + return null; + } + switch (device) { + case EARPIECE: + return TalkCallInterop.AUDIO_ROUTE_EARPIECE; + case BLUETOOTH: + case BLUETOOTH_SCO: + return TalkCallInterop.AUDIO_ROUTE_BLUETOOTH; + case WIRED_HEADSET: + return TalkCallInterop.AUDIO_ROUTE_WIRED_HEADSET; + case SPEAKER_PHONE: + return TalkCallInterop.AUDIO_ROUTE_SPEAKER; + default: + return null; + } + } + + private static AudioDevice fromTelecomAudioRoute(String route) { + if (route == null) { + return AudioDevice.NONE; + } + switch (route) { + case TalkCallInterop.AUDIO_ROUTE_EARPIECE: + return AudioDevice.EARPIECE; + case TalkCallInterop.AUDIO_ROUTE_BLUETOOTH: + case TalkCallInterop.AUDIO_ROUTE_EXTERNAL: + // The current Talk picker has one external wireless output row. + // Treat Telecom's streaming endpoint as that row until the UI + // grows named endpoint support. + return AudioDevice.BLUETOOTH; + case TalkCallInterop.AUDIO_ROUTE_WIRED_HEADSET: + return AudioDevice.WIRED_HEADSET; + case TalkCallInterop.AUDIO_ROUTE_SPEAKER: + return AudioDevice.SPEAKER_PHONE; + default: + return AudioDevice.NONE; + } + } + /** * AudioDevice is the names of possible audio devices that we currently support. */ From 8a377e63b6976893fd6d3b9556c966a79fe44670 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:37:08 -0400 Subject: [PATCH 48/73] fix(auto): mark Telecom audio ownership before WebRTC starts --- .../nextcloud/talk/call/TalkCallInterop.kt | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt index a131f075b4b..11def468b6c 100644 --- a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt +++ b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt @@ -8,6 +8,7 @@ package com.nextcloud.talk.call import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.os.Bundle import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN @@ -65,10 +66,12 @@ object TalkCallInterop { val roomToken = callExtras.getString(KEY_ROOM_TOKEN).orEmpty() if (accountId < 0L || roomToken.isBlank()) return + val key = callKey(accountId, roomToken) + prepareTelecomAudioManagementIfAvailable(context, key) send( context, Intent(ACTION_INCOMING_CALL) - .putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken)) + .putExtra(EXTRA_CALL_KEY, key) .putExtra(EXTRA_CALL_EXTRAS, Bundle(callExtras)) .putExtra(EXTRA_DISPLAY_NAME, displayName) .putExtra(EXTRA_INCOMING, true) @@ -86,10 +89,12 @@ object TalkCallInterop { callExtras: Bundle ) { if (accountId < 0L || roomToken.isBlank()) return + val key = callKey(accountId, roomToken) + prepareTelecomAudioManagementIfAvailable(context, key) send( context, Intent(ACTION_CALL_STARTED) - .putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken)) + .putExtra(EXTRA_CALL_KEY, key) .putExtra(EXTRA_CALL_EXTRAS, Bundle(callExtras)) .putExtra(EXTRA_DISPLAY_NAME, displayName) .putExtra(EXTRA_INCOMING, incoming) @@ -130,7 +135,7 @@ object TalkCallInterop { } fun beginTelecomAudioManagement(context: Context, callKey: String) { - if (callKey.isBlank()) return + if (callKey.isBlank() || activeTelecomCallKey == callKey) return activeTelecomCallKey = callKey telecomCurrentAudioRoute = null telecomAvailableAudioRoutes = emptyArray() @@ -172,6 +177,15 @@ object TalkCallInterop { send(context, Intent(action).putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken))) } + @Suppress("DEPRECATION") + private fun prepareTelecomAudioManagementIfAvailable(context: Context, callKey: String) { + val probe = Intent(ACTION_CALL_STARTED).setPackage(context.packageName) + val receivers = context.packageManager.queryBroadcastReceivers(probe, PackageManager.MATCH_ALL) + if (receivers.isNotEmpty()) { + beginTelecomAudioManagement(context, callKey) + } + } + private fun send(context: Context, intent: Intent) { intent.setPackage(context.packageName) context.sendBroadcast(intent) From 33442995bc5a3a8a2cfd9332cb2412215a481457 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 16:49:55 -0400 Subject: [PATCH 49/73] fix(auto): route streaming endpoints from Talk audio picker Assisted-by: ChatGPT:GPT-5.6-Sol --- .../com/nextcloud/talk/auto/call/TalkTelecomManager.kt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index 0a1fb62f295..b0ba8b6399e 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -127,7 +127,15 @@ class TalkTelecomManager private constructor(context: Context) { val control = managed.control ?: return val endpoint = managed.availableEndpoints.firstOrNull { endpoint -> routeForEndpoint(endpoint) == route - } ?: run { + } ?: if (route == TalkCallInterop.AUDIO_ROUTE_BLUETOOTH) { + managed.availableEndpoints.firstOrNull { endpoint -> + routeForEndpoint(endpoint) == TalkCallInterop.AUDIO_ROUTE_EXTERNAL + } + } else { + null + } + + if (endpoint == null) { Log.w(TAG, "No Telecom endpoint for requested route $route on $callKey") return } From 75819cf35b2f551f21aaeeb364e3a31ddd904c38 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:11:49 -0400 Subject: [PATCH 50/73] feat(auto): show recent Talk conversations Assisted-by: ChatGPT:GPT-5.6-Sol --- .../talk/auto/TalkConversationsScreen.kt | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt new file mode 100644 index 00000000000..ce988430629 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt @@ -0,0 +1,250 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto + +import android.content.Intent +import android.os.Bundle +import androidx.car.app.CarContext +import androidx.car.app.Screen +import androidx.car.app.messaging.model.CarMessage +import androidx.car.app.messaging.model.ConversationCallback +import androidx.car.app.messaging.model.ConversationItem +import androidx.car.app.model.Action +import androidx.car.app.model.CarText +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.core.app.Person +import androidx.core.app.RemoteInput +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.nextcloud.talk.data.database.dao.ChatMessagesDao +import com.nextcloud.talk.data.database.dao.ConversationsDao +import com.nextcloud.talk.data.database.model.ChatMessageEntity +import com.nextcloud.talk.data.database.model.ConversationEntity +import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.models.json.conversations.ConversationEnums +import com.nextcloud.talk.receivers.DirectReplyReceiver +import com.nextcloud.talk.receivers.MarkAsReadReceiver +import com.nextcloud.talk.utils.NotificationUtils +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID +import com.nextcloud.talk.utils.database.user.CurrentUserProvider +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch + +internal class TalkConversationsScreen( + carContext: CarContext, + private val currentUserProvider: CurrentUserProvider, + private val conversationsDao: ConversationsDao, + private val chatMessagesDao: ChatMessagesDao +) : Screen(carContext) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + + private var user: User? = null + private var snapshots: List = emptyList() + private var loading = true + private var errorMessage: String? = null + + init { + lifecycle.addObserver( + object : DefaultLifecycleObserver { + override fun onDestroy(owner: LifecycleOwner) { + scope.cancel() + } + } + ) + observeConversations() + } + + override fun onGetTemplate(): Template { + val itemList = ItemList.Builder() + + when { + loading -> itemList.addItem(Row.Builder().setTitle("Loading conversations…").build()) + errorMessage != null -> itemList.addItem(Row.Builder().setTitle(errorMessage!!).build()) + snapshots.isEmpty() -> itemList.addItem(Row.Builder().setTitle("No recent conversations").build()) + else -> { + val activeUser = user ?: return buildListTemplate(itemList.build()) + snapshots.forEach { snapshot -> + itemList.addItem(buildConversationItem(activeUser, snapshot)) + } + } + } + + return buildListTemplate(itemList.build()) + } + + private fun observeConversations() { + scope.launch { + try { + val activeUser = currentUserProvider.getCurrentUser().getOrElse { throw it } + val accountId = activeUser.id ?: error("Current Talk account has no local ID") + user = activeUser + + conversationsDao.getConversationsForUser(accountId).collectLatest { conversations -> + snapshots = conversations + .asSequence() + .filter(::isVisibleConversation) + .sortedByDescending(ConversationEntity::lastActivity) + .take(MAX_CONVERSATIONS) + .map { conversation -> + val messages = chatMessagesDao + .getMessagesForConversation(conversation.internalId, null) + .first() + .asSequence() + .filter { !it.deleted && it.message.isNotBlank() } + .take(MAX_MESSAGES_PER_CONVERSATION) + .toList() + .asReversed() + + ConversationSnapshot(conversation, messages) + } + .toList() + + loading = false + errorMessage = null + invalidate() + } + } catch (_: Throwable) { + loading = false + errorMessage = "Talk conversations are unavailable" + invalidate() + } + } + } + + private fun buildConversationItem(activeUser: User, snapshot: ConversationSnapshot): ConversationItem { + val conversation = snapshot.conversation + val self = Person.Builder() + .setName(activeUser.displayName ?: activeUser.userId ?: activeUser.username ?: "You") + .setKey(activeUser.userId ?: activeUser.username ?: activeUser.id.toString()) + .build() + + val messages = snapshot.messages.map { message -> + buildCarMessage(activeUser, conversation, message) + } + + val callback = object : ConversationCallback { + override fun onMarkAsRead() { + val newestMessageId = snapshot.messages.lastOrNull()?.id ?: return + sendMarkAsRead(conversation, newestMessageId) + } + + override fun onTextReply(replyText: String) { + if (replyText.isNotBlank() && + conversation.conversationReadOnlyState == + ConversationEnums.ConversationReadOnlyState.CONVERSATION_READ_WRITE + ) { + sendDirectReply(conversation, replyText) + } + } + } + + return ConversationItem.Builder( + conversation.internalId, + CarText.create(conversation.displayName), + self, + messages, + callback + ) + .setGroupConversation(isGroupConversation(conversation)) + .build() + } + + private fun buildCarMessage( + activeUser: User, + conversation: ConversationEntity, + message: ChatMessageEntity + ): CarMessage { + val sentBySelf = message.actorId == activeUser.userId + val sender = if (sentBySelf) { + null + } else { + Person.Builder() + .setName(message.actorDisplayName.ifBlank { "Talk user" }) + .setKey("${conversation.internalId}:${message.actorType}:${message.actorId}") + .build() + } + + val timestampMillis = if (message.timestamp < TIMESTAMP_MILLISECONDS_THRESHOLD) { + message.timestamp * 1000L + } else { + message.timestamp + } + + return CarMessage.Builder() + .setBody(CarText.create(message.message)) + .setRead(sentBySelf || message.id <= conversation.lastReadMessage.toLong()) + .setReceivedTimeEpochMillis(timestampMillis) + .apply { sender?.let(::setSender) } + .build() + } + + private fun sendDirectReply(conversation: ConversationEntity, replyText: String) { + val intent = Intent(carContext, DirectReplyReceiver::class.java) + .putExtra(KEY_SYSTEM_NOTIFICATION_ID, 0) + .putExtra(KEY_ROOM_TOKEN, conversation.token) + .putExtra(KEY_INTERNAL_USER_ID, conversation.accountId) + + val remoteInput = RemoteInput.Builder(NotificationUtils.KEY_DIRECT_REPLY).build() + val results = Bundle().apply { + putCharSequence(NotificationUtils.KEY_DIRECT_REPLY, replyText) + } + RemoteInput.addResultsToIntent(arrayOf(remoteInput), intent, results) + carContext.sendBroadcast(intent) + } + + private fun sendMarkAsRead(conversation: ConversationEntity, messageId: Long) { + carContext.sendBroadcast( + Intent(carContext, MarkAsReadReceiver::class.java) + .putExtra(KEY_SYSTEM_NOTIFICATION_ID, 0) + .putExtra(KEY_ROOM_TOKEN, conversation.token) + .putExtra(KEY_INTERNAL_USER_ID, conversation.accountId) + .putExtra(KEY_MESSAGE_ID, messageId.toInt()) + ) + } + + private fun buildListTemplate(itemList: ItemList): Template = + ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.BACK) + .setTitle("Messages") + .build() + ) + .setSingleList(itemList) + .build() + + private fun isVisibleConversation(conversation: ConversationEntity): Boolean = + conversation.type != ConversationEnums.ConversationType.DUMMY && + conversation.type != ConversationEnums.ConversationType.ROOM_SYSTEM + + private fun isGroupConversation(conversation: ConversationEntity): Boolean = + conversation.type == ConversationEnums.ConversationType.ROOM_GROUP_CALL || + conversation.type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL + + private data class ConversationSnapshot( + val conversation: ConversationEntity, + val messages: List + ) + + companion object { + private const val MAX_CONVERSATIONS = 10 + private const val MAX_MESSAGES_PER_CONVERSATION = 5 + private const val TIMESTAMP_MILLISECONDS_THRESHOLD = 10_000_000_000L + } +} From 78b4e8d904cc5cf4ac2e52cdde30d6510c0fcebe Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:12:09 -0400 Subject: [PATCH 51/73] feat(auto): connect messages screen to Talk data Assisted-by: ChatGPT:GPT-5.6-Sol --- .../nextcloud/talk/auto/TalkCarAppService.kt | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt index 329e8046b20..d153cd904e9 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt @@ -19,12 +19,29 @@ import androidx.car.app.model.ListTemplate import androidx.car.app.model.Row import androidx.car.app.model.Template import androidx.car.app.validation.HostValidator +import autodagger.AutoInjector +import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.auto.call.TalkTelecomManager +import com.nextcloud.talk.data.database.dao.ChatMessagesDao +import com.nextcloud.talk.data.database.dao.ConversationsDao +import com.nextcloud.talk.utils.database.user.CurrentUserProvider +import javax.inject.Inject /** Android Auto entry point for Talk messaging and calling. */ +@AutoInjector(NextcloudTalkApplication::class) class TalkCarAppService : CarAppService() { + @Inject + lateinit var currentUserProvider: CurrentUserProvider + + @Inject + lateinit var conversationsDao: ConversationsDao + + @Inject + lateinit var chatMessagesDao: ChatMessagesDao + override fun onCreate() { super.onCreate() + NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) TalkTelecomManager.get(applicationContext).registerWithTelecom() } @@ -37,27 +54,38 @@ class TalkCarAppService : CarAppService() { .build() } - override fun onCreateSession(): Session = TalkCarSession() + override fun onCreateSession(): Session = + TalkCarSession(currentUserProvider, conversationsDao, chatMessagesDao) } -private class TalkCarSession : Session() { - override fun onCreateScreen(intent: Intent): Screen = TalkCarHomeScreen(carContext) +private class TalkCarSession( + private val currentUserProvider: CurrentUserProvider, + private val conversationsDao: ConversationsDao, + private val chatMessagesDao: ChatMessagesDao +) : Session() { + override fun onCreateScreen(intent: Intent): Screen = + TalkCarHomeScreen(carContext, currentUserProvider, conversationsDao, chatMessagesDao) } -private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { +private class TalkCarHomeScreen( + carContext: CarContext, + private val currentUserProvider: CurrentUserProvider, + private val conversationsDao: ConversationsDao, + private val chatMessagesDao: ChatMessagesDao +) : Screen(carContext) { override fun onGetTemplate(): Template { val items = ItemList.Builder() .addItem( Row.Builder() .setTitle("Messages") - .addText("Read, reply to, and start Talk conversations") + .addText("Read and reply to recent Talk conversations") .setOnClickListener { screenManager.push( - TalkCarStatusScreen( + TalkConversationsScreen( carContext, - "Messages", - "Messaging notifications and voice replies are enabled. " + - "Conversation history and contact selection are the next layer." + currentUserProvider, + conversationsDao, + chatMessagesDao ) ) } @@ -66,14 +94,14 @@ private class TalkCarHomeScreen(carContext: CarContext) : Screen(carContext) { .addItem( Row.Builder() .setTitle("Calls") - .addText("Start and control Talk voice calls") + .addText("Control Talk voice calls through Android Telecom") .setOnClickListener { screenManager.push( TalkCarStatusScreen( carContext, "Calls", - "Talk is registered with Android Telecom. " + - "The next layer connects Telecom callbacks to Talk WebRTC calls." + "Incoming and active Talk calls are connected to Android Telecom. " + + "Contact-selected outgoing calls are the next call UI layer." ) ) } From 612a7e665aa23dd1ae7d9394de0c52bd6f978778 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:13:24 -0400 Subject: [PATCH 52/73] fix(auto): preserve messaging screen cancellation Assisted-by: ChatGPT:GPT-5.6-Sol --- .../com/nextcloud/talk/auto/TalkConversationsScreen.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt index ce988430629..44db7678e18 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt @@ -38,6 +38,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_MESSAGE_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID import com.nextcloud.talk.utils.database.user.CurrentUserProvider +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob @@ -119,7 +120,9 @@ internal class TalkConversationsScreen( errorMessage = null invalidate() } - } catch (_: Throwable) { + } catch (e: CancellationException) { + throw e + } catch (_: Exception) { loading = false errorMessage = "Talk conversations are unavailable" invalidate() @@ -131,7 +134,7 @@ internal class TalkConversationsScreen( val conversation = snapshot.conversation val self = Person.Builder() .setName(activeUser.displayName ?: activeUser.userId ?: activeUser.username ?: "You") - .setKey(activeUser.userId ?: activeUser.username ?: activeUser.id.toString()) + .setKey(activeUser.userId ?: activeUser.username ?: activeUser.id?.toString() ?: "self") .build() val messages = snapshot.messages.map { message -> From 391a79715c57cb35743f8843abb928ce32a3b2dd Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:29:24 -0400 Subject: [PATCH 53/73] fix(auto): load conversation messages from suspend context Assisted-by: ChatGPT:GPT-5.6-Sol --- .../talk/auto/TalkConversationsScreen.kt | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt index 44db7678e18..6ccc8180edd 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkConversationsScreen.kt @@ -97,25 +97,28 @@ internal class TalkConversationsScreen( user = activeUser conversationsDao.getConversationsForUser(accountId).collectLatest { conversations -> - snapshots = conversations + val recentConversations = conversations .asSequence() .filter(::isVisibleConversation) .sortedByDescending(ConversationEntity::lastActivity) .take(MAX_CONVERSATIONS) - .map { conversation -> - val messages = chatMessagesDao - .getMessagesForConversation(conversation.internalId, null) - .first() - .asSequence() - .filter { !it.deleted && it.message.isNotBlank() } - .take(MAX_MESSAGES_PER_CONVERSATION) - .toList() - .asReversed() - - ConversationSnapshot(conversation, messages) - } .toList() + val updatedSnapshots = mutableListOf() + for (conversation in recentConversations) { + val messages = chatMessagesDao + .getMessagesForConversation(conversation.internalId, null) + .first() + .asSequence() + .filter { !it.deleted && it.message.isNotBlank() } + .take(MAX_MESSAGES_PER_CONVERSATION) + .toList() + .asReversed() + + updatedSnapshots.add(ConversationSnapshot(conversation, messages)) + } + snapshots = updatedSnapshots + loading = false errorMessage = null invalidate() @@ -184,7 +187,7 @@ internal class TalkConversationsScreen( } val timestampMillis = if (message.timestamp < TIMESTAMP_MILLISECONDS_THRESHOLD) { - message.timestamp * 1000L + message.timestamp * MILLISECONDS_PER_SECOND } else { message.timestamp } @@ -199,7 +202,7 @@ internal class TalkConversationsScreen( private fun sendDirectReply(conversation: ConversationEntity, replyText: String) { val intent = Intent(carContext, DirectReplyReceiver::class.java) - .putExtra(KEY_SYSTEM_NOTIFICATION_ID, 0) + .putExtra(KEY_SYSTEM_NOTIFICATION_ID, NO_SYSTEM_NOTIFICATION_ID) .putExtra(KEY_ROOM_TOKEN, conversation.token) .putExtra(KEY_INTERNAL_USER_ID, conversation.accountId) @@ -214,7 +217,7 @@ internal class TalkConversationsScreen( private fun sendMarkAsRead(conversation: ConversationEntity, messageId: Long) { carContext.sendBroadcast( Intent(carContext, MarkAsReadReceiver::class.java) - .putExtra(KEY_SYSTEM_NOTIFICATION_ID, 0) + .putExtra(KEY_SYSTEM_NOTIFICATION_ID, NO_SYSTEM_NOTIFICATION_ID) .putExtra(KEY_ROOM_TOKEN, conversation.token) .putExtra(KEY_INTERNAL_USER_ID, conversation.accountId) .putExtra(KEY_MESSAGE_ID, messageId.toInt()) @@ -240,14 +243,13 @@ internal class TalkConversationsScreen( conversation.type == ConversationEnums.ConversationType.ROOM_GROUP_CALL || conversation.type == ConversationEnums.ConversationType.ROOM_PUBLIC_CALL - private data class ConversationSnapshot( - val conversation: ConversationEntity, - val messages: List - ) + private data class ConversationSnapshot(val conversation: ConversationEntity, val messages: List) companion object { private const val MAX_CONVERSATIONS = 10 private const val MAX_MESSAGES_PER_CONVERSATION = 5 + private const val MILLISECONDS_PER_SECOND = 1000L + private const val NO_SYSTEM_NOTIFICATION_ID = 0 private const val TIMESTAMP_MILLISECONDS_THRESHOLD = 10_000_000_000L } } From 61ad52af2421d1d0fb506654f8cc826fbc4625f7 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:30:21 -0400 Subject: [PATCH 54/73] style(auto): align car service with Kotlin formatting Assisted-by: ChatGPT:GPT-5.6-Sol --- .../java/com/nextcloud/talk/auto/TalkCarAppService.kt | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt index d153cd904e9..6efb803f55f 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt @@ -54,8 +54,7 @@ class TalkCarAppService : CarAppService() { .build() } - override fun onCreateSession(): Session = - TalkCarSession(currentUserProvider, conversationsDao, chatMessagesDao) + override fun onCreateSession(): Session = TalkCarSession(currentUserProvider, conversationsDao, chatMessagesDao) } private class TalkCarSession( @@ -121,11 +120,8 @@ private class TalkCarHomeScreen( } } -private class TalkCarStatusScreen( - carContext: CarContext, - private val title: String, - private val status: String -) : Screen(carContext) { +private class TalkCarStatusScreen(carContext: CarContext, private val title: String, private val status: String) : + Screen(carContext) { override fun onGetTemplate(): Template = ListTemplate.Builder() .setHeader( From 51ebfc7246aa58fcf2798976e5837595bb3bcb6b Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:30:57 -0400 Subject: [PATCH 55/73] style(auto): format Telecom lifecycle methods Assisted-by: ChatGPT:GPT-5.6-Sol --- .../talk/auto/call/TalkTelecomManager.kt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index b0ba8b6399e..b67fe36b7a5 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -55,12 +55,7 @@ class TalkTelecomManager private constructor(context: Context) { registered = true } - fun onIncomingCall( - callKey: String, - callExtras: Bundle, - displayName: String, - video: Boolean - ) { + fun onIncomingCall(callKey: String, callExtras: Bundle, displayName: String, video: Boolean) { addCallIfNeeded( callKey = callKey, callExtras = callExtras, @@ -71,13 +66,7 @@ class TalkTelecomManager private constructor(context: Context) { ) } - fun onCallStarted( - callKey: String, - callExtras: Bundle, - displayName: String, - incoming: Boolean, - video: Boolean - ) { + fun onCallStarted(callKey: String, callExtras: Bundle, displayName: String, incoming: Boolean, video: Boolean) { val existing = calls[callKey] if (existing != null) { existing.activityStarted = true From 7ba095850f7192a29ae5c617064e2c6be1de7a7d Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:33:38 -0400 Subject: [PATCH 56/73] feat(auto): add outgoing call conversation picker Assisted-by: ChatGPT:GPT-5.6-Sol --- .../nextcloud/talk/auto/TalkCallsScreen.kt | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt new file mode 100644 index 00000000000..4a164e9a795 --- /dev/null +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt @@ -0,0 +1,139 @@ +/* + * Nextcloud Talk - Android Client + * + * SPDX-FileCopyrightText: 2026 Michael Avery + * SPDX-License-Identifier: GPL-3.0-or-later + */ +package com.nextcloud.talk.auto + +import android.content.ActivityNotFoundException +import android.content.Intent +import androidx.car.app.CarContext +import androidx.car.app.CarToast +import androidx.car.app.Screen +import androidx.car.app.model.Action +import androidx.car.app.model.Header +import androidx.car.app.model.ItemList +import androidx.car.app.model.ListTemplate +import androidx.car.app.model.Row +import androidx.car.app.model.Template +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import com.nextcloud.talk.chat.ChatActivity +import com.nextcloud.talk.data.database.dao.ConversationsDao +import com.nextcloud.talk.data.database.model.ConversationEntity +import com.nextcloud.talk.models.json.conversations.ConversationEnums +import com.nextcloud.talk.utils.bundle.BundleKeys +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN +import com.nextcloud.talk.utils.database.user.CurrentUserProvider +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +internal class TalkCallsScreen( + carContext: CarContext, + private val currentUserProvider: CurrentUserProvider, + private val conversationsDao: ConversationsDao +) : Screen(carContext) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) + + private var conversations: List = emptyList() + private var loading = true + private var errorMessage: String? = null + + init { + lifecycle.addObserver( + object : DefaultLifecycleObserver { + override fun onDestroy(owner: LifecycleOwner) { + scope.cancel() + } + } + ) + observeConversations() + } + + override fun onGetTemplate(): Template { + val itemList = ItemList.Builder() + + when { + loading -> itemList.addItem(Row.Builder().setTitle("Loading calls…").build()) + errorMessage != null -> itemList.addItem(Row.Builder().setTitle(errorMessage!!).build()) + conversations.isEmpty() -> itemList.addItem(Row.Builder().setTitle("No conversations available for calls").build()) + else -> conversations.forEach { conversation -> + itemList.addItem( + Row.Builder() + .setTitle(conversation.displayName) + .addText(if (conversation.hasCall) "Join ongoing Talk call" else "Start voice call") + .setOnClickListener { startVoiceCall(conversation) } + .build() + ) + } + } + + return ListTemplate.Builder() + .setHeader( + Header.Builder() + .setStartHeaderAction(Action.BACK) + .setTitle("Calls") + .build() + ) + .setSingleList(itemList.build()) + .build() + } + + private fun observeConversations() { + scope.launch { + try { + val activeUser = currentUserProvider.getCurrentUser().getOrElse { throw it } + val accountId = activeUser.id ?: error("Current Talk account has no local ID") + + conversationsDao.getConversationsForUser(accountId).collectLatest { conversationList -> + conversations = conversationList + .asSequence() + .filter(::isCallableConversation) + .sortedByDescending(ConversationEntity::lastActivity) + .take(MAX_CONVERSATIONS) + .toList() + loading = false + errorMessage = null + invalidate() + } + } catch (e: CancellationException) { + throw e + } catch (_: Exception) { + loading = false + errorMessage = "Talk calls are unavailable" + invalidate() + } + } + } + + private fun startVoiceCall(conversation: ConversationEntity) { + try { + carContext.startActivity( + Intent(carContext, ChatActivity::class.java).apply { + putExtra(KEY_ROOM_TOKEN, conversation.token) + putExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, true) + putExtra(KEY_CALL_VOICE_ONLY, true) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + ) + } catch (_: ActivityNotFoundException) { + CarToast.makeText(carContext, "Unable to start Talk call", CarToast.LENGTH_SHORT).show() + } + } + + private fun isCallableConversation(conversation: ConversationEntity): Boolean = + conversation.type != ConversationEnums.ConversationType.DUMMY && + conversation.type != ConversationEnums.ConversationType.ROOM_SYSTEM && + (conversation.canStartCall || conversation.hasCall) + + companion object { + private const val MAX_CONVERSATIONS = 10 + } +} From 0b92bff77454f3cd8e7df82732ec1da18d5c7218 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:33:52 -0400 Subject: [PATCH 57/73] feat(auto): open call picker from car home Assisted-by: ChatGPT:GPT-5.6-Sol --- .../nextcloud/talk/auto/TalkCarAppService.kt | 27 +++---------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt index 6efb803f55f..ea87dbeb0bf 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCarAppService.kt @@ -93,14 +93,13 @@ private class TalkCarHomeScreen( .addItem( Row.Builder() .setTitle("Calls") - .addText("Control Talk voice calls through Android Telecom") + .addText("Start or join Talk voice calls") .setOnClickListener { screenManager.push( - TalkCarStatusScreen( + TalkCallsScreen( carContext, - "Calls", - "Incoming and active Talk calls are connected to Android Telecom. " + - "Contact-selected outgoing calls are the next call UI layer." + currentUserProvider, + conversationsDao ) ) } @@ -119,21 +118,3 @@ private class TalkCarHomeScreen( .build() } } - -private class TalkCarStatusScreen(carContext: CarContext, private val title: String, private val status: String) : - Screen(carContext) { - override fun onGetTemplate(): Template = - ListTemplate.Builder() - .setHeader( - Header.Builder() - .setStartHeaderAction(Action.BACK) - .setTitle(title) - .build() - ) - .setSingleList( - ItemList.Builder() - .addItem(Row.Builder().setTitle(status).build()) - .build() - ) - .build() -} From 721efaabf5f0711be6029432d399e804ea120f0c Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:34:52 -0400 Subject: [PATCH 58/73] style(auto): format incoming call bridge Assisted-by: ChatGPT:GPT-5.6-Sol --- .../main/java/com/nextcloud/talk/call/TalkCallInterop.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt index 11def468b6c..413bc24f1f4 100644 --- a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt +++ b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt @@ -56,12 +56,7 @@ object TalkCallInterop { fun callKey(accountId: Long, roomToken: String): String = "$accountId@$roomToken" - fun notifyIncomingCall( - context: Context, - callExtras: Bundle, - displayName: String, - video: Boolean - ) { + fun notifyIncomingCall(context: Context, callExtras: Bundle, displayName: String, video: Boolean) { val accountId = callExtras.getLong(KEY_INTERNAL_USER_ID, -1L) val roomToken = callExtras.getString(KEY_ROOM_TOKEN).orEmpty() if (accountId < 0L || roomToken.isBlank()) return From c67e07e9860b423b29b557ceacccc2a8075e1501 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:36:01 -0400 Subject: [PATCH 59/73] ci(auto): validate outgoing call picker Assisted-by: ChatGPT:GPT-5.6-Sol --- .../android-auto-validate-outgoing.yml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 .github/workflows/android-auto-validate-outgoing.yml diff --git a/.github/workflows/android-auto-validate-outgoing.yml b/.github/workflows/android-auto-validate-outgoing.yml new file mode 100644 index 00000000000..d6439e4a450 --- /dev/null +++ b/.github/workflows/android-auto-validate-outgoing.yml @@ -0,0 +1,66 @@ +name: Android Auto - validate outgoing calls + +on: + push: + branches: + - android-auto-outgoing-calls + paths: + - .github/workflows/android-auto-validate-outgoing.yml + +permissions: + contents: write + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto-outgoing-calls + fetch-depth: 0 + + - name: Format imported notification condition + shell: bash + run: | + python3 - <<'PY' + from pathlib import Path + + path = Path('app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt') + text = path.read_text() + old = ' if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) && pushMessage.notificationUser != null) {\n' + new = ( + ' if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) &&\n' + ' pushMessage.notificationUser != null\n' + ' ) {\n' + ) + if old in text: + text = text.replace(old, new, 1) + elif new not in text: + raise SystemExit('Notification condition did not match expected source') + path.write_text(text) + PY + + - name: Commit formatting patch + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt + if ! git diff --cached --quiet; then + git commit -m $'style(auto): wrap messaging notification condition\n\nAssisted-by: ChatGPT:GPT-5.6-Sol' + fi + + - name: Compile Android Auto flavors + run: ./gradlew :app:compileGplayDebugKotlin :app:compileGenericDebugKotlin --stacktrace + + - name: Run Kotlin style check + run: ./gradlew ktlintCheck --stacktrace + + - name: Push source patch + shell: bash + run: | + set -euo pipefail + git fetch origin android-auto-outgoing-calls + git rebase origin/android-auto-outgoing-calls + git push origin HEAD:android-auto-outgoing-calls From e8da5305dcb96617b32e65a71f2595f45d52edff Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:48:19 -0400 Subject: [PATCH 60/73] style(auto): format empty call picker state Assisted-by: ChatGPT:GPT-5.6-Sol --- .../java/com/nextcloud/talk/auto/TalkCallsScreen.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt index 4a164e9a795..9a0c210f1de 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt @@ -63,7 +63,14 @@ internal class TalkCallsScreen( when { loading -> itemList.addItem(Row.Builder().setTitle("Loading calls…").build()) errorMessage != null -> itemList.addItem(Row.Builder().setTitle(errorMessage!!).build()) - conversations.isEmpty() -> itemList.addItem(Row.Builder().setTitle("No conversations available for calls").build()) + conversations.isEmpty() -> { + itemList.addItem( + Row.Builder() + .setTitle("No conversations available for calls") + .build() + ) + } + else -> conversations.forEach { conversation -> itemList.addItem( Row.Builder() From b6483f3f8d13fec198f2a06582bd32d1be076b57 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 21:48:35 -0400 Subject: [PATCH 61/73] ci(auto): rerun outgoing call validation Assisted-by: ChatGPT:GPT-5.6-Sol --- .github/workflows/android-auto-validate-outgoing.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/android-auto-validate-outgoing.yml b/.github/workflows/android-auto-validate-outgoing.yml index d6439e4a450..58645b1d0bc 100644 --- a/.github/workflows/android-auto-validate-outgoing.yml +++ b/.github/workflows/android-auto-validate-outgoing.yml @@ -6,6 +6,7 @@ on: - android-auto-outgoing-calls paths: - .github/workflows/android-auto-validate-outgoing.yml + - app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt permissions: contents: write From 31980bcca395df9dfa47ca2289f4a6e7397e0963 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 01:48:48 +0000 Subject: [PATCH 62/73] style(auto): wrap messaging notification condition Assisted-by: ChatGPT:GPT-5.6-Sol --- .../main/java/com/nextcloud/talk/jobs/NotificationWorker.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt index b66fb16bed7..ae5abbbf7bc 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -713,7 +713,9 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val systemNotificationId: Int = activeStatusBarNotification?.id ?: calculateCRC32(System.currentTimeMillis().toString()).toInt() - if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) && pushMessage.notificationUser != null) { + if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) && + pushMessage.notificationUser != null + ) { notificationBuilder.setOnlyAlertOnce(false) val senderAvatar = loadSenderAvatar(pushMessage.notificationUser) val imageUri = imagePreviewUrl?.let { loadImageBitmapSync(it) }?.let { From fb5b8d521002f089c49c8ba4ca4f3f4084a6ba60 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:02:06 -0400 Subject: [PATCH 63/73] ci(auto): remove temporary outgoing validator Assisted-by: ChatGPT:GPT-5.6-Sol --- .../android-auto-validate-outgoing.yml | 67 ------------------- 1 file changed, 67 deletions(-) delete mode 100644 .github/workflows/android-auto-validate-outgoing.yml diff --git a/.github/workflows/android-auto-validate-outgoing.yml b/.github/workflows/android-auto-validate-outgoing.yml deleted file mode 100644 index 58645b1d0bc..00000000000 --- a/.github/workflows/android-auto-validate-outgoing.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Android Auto - validate outgoing calls - -on: - push: - branches: - - android-auto-outgoing-calls - paths: - - .github/workflows/android-auto-validate-outgoing.yml - - app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt - -permissions: - contents: write - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto-outgoing-calls - fetch-depth: 0 - - - name: Format imported notification condition - shell: bash - run: | - python3 - <<'PY' - from pathlib import Path - - path = Path('app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt') - text = path.read_text() - old = ' if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) && pushMessage.notificationUser != null) {\n' - new = ( - ' if ((TYPE_CHAT == pushMessage.type || TYPE_REMINDER == pushMessage.type) &&\n' - ' pushMessage.notificationUser != null\n' - ' ) {\n' - ) - if old in text: - text = text.replace(old, new, 1) - elif new not in text: - raise SystemExit('Notification condition did not match expected source') - path.write_text(text) - PY - - - name: Commit formatting patch - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt - if ! git diff --cached --quiet; then - git commit -m $'style(auto): wrap messaging notification condition\n\nAssisted-by: ChatGPT:GPT-5.6-Sol' - fi - - - name: Compile Android Auto flavors - run: ./gradlew :app:compileGplayDebugKotlin :app:compileGenericDebugKotlin --stacktrace - - - name: Run Kotlin style check - run: ./gradlew ktlintCheck --stacktrace - - - name: Push source patch - shell: bash - run: | - set -euo pipefail - git fetch origin android-auto-outgoing-calls - git rebase origin/android-auto-outgoing-calls - git push origin HEAD:android-auto-outgoing-calls From 10909e501307c0d6727a9626fb6e9008863bfb39 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:02:56 -0400 Subject: [PATCH 64/73] feat(auto): request microphone permission from car Assisted-by: ChatGPT:GPT-5.6-Sol --- .../nextcloud/talk/auto/TalkCallsScreen.kt | 50 ++++++++++++++++--- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt index 9a0c210f1de..e252babda8c 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt @@ -6,8 +6,10 @@ */ package com.nextcloud.talk.auto +import android.Manifest import android.content.ActivityNotFoundException import android.content.Intent +import android.content.pm.PackageManager import androidx.car.app.CarContext import androidx.car.app.CarToast import androidx.car.app.Screen @@ -15,8 +17,10 @@ import androidx.car.app.model.Action import androidx.car.app.model.Header import androidx.car.app.model.ItemList import androidx.car.app.model.ListTemplate +import androidx.car.app.model.ParkedOnlyOnClickListener import androidx.car.app.model.Row import androidx.car.app.model.Template +import androidx.core.content.ContextCompat import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import com.nextcloud.talk.chat.ChatActivity @@ -72,13 +76,21 @@ internal class TalkCallsScreen( } else -> conversations.forEach { conversation -> - itemList.addItem( - Row.Builder() - .setTitle(conversation.displayName) - .addText(if (conversation.hasCall) "Join ongoing Talk call" else "Start voice call") - .setOnClickListener { startVoiceCall(conversation) } - .build() - ) + val row = Row.Builder() + .setTitle(conversation.displayName) + .addText(if (conversation.hasCall) "Join ongoing Talk call" else "Start voice call") + + if (hasMicrophonePermission()) { + row.setOnClickListener { startVoiceCall(conversation) } + } else { + row.setOnClickListener( + ParkedOnlyOnClickListener.create { + requestMicrophonePermissionAndStart(conversation) + } + ) + } + + itemList.addItem(row.build()) } } @@ -120,6 +132,30 @@ internal class TalkCallsScreen( } } + private fun hasMicrophonePermission(): Boolean = + ContextCompat.checkSelfPermission(carContext, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED + + private fun requestMicrophonePermissionAndStart(conversation: ConversationEntity) { + carContext.requestPermissions(listOf(Manifest.permission.RECORD_AUDIO)) { grantedPermissions, _ -> + if (Manifest.permission.RECORD_AUDIO in grantedPermissions) { + startVoiceCall(conversation) + } else { + CarToast.makeText( + carContext, + "Microphone permission is required for Talk calls", + CarToast.LENGTH_LONG + ).show() + } + invalidate() + } + + CarToast.makeText( + carContext, + "Grant microphone access on your phone", + CarToast.LENGTH_LONG + ).show() + } + private fun startVoiceCall(conversation: ConversationEntity) { try { carContext.startActivity( From 05c0d4a3f06dda83175b22d69ceba9d5905140ea Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:03:26 -0400 Subject: [PATCH 65/73] fix(auto): refresh messages after direct reply Assisted-by: ChatGPT:GPT-5.6-Sol --- .../java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt b/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt index 0620602e3ac..309710f8fad 100644 --- a/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt +++ b/app/src/main/java/com/nextcloud/talk/receivers/DirectReplyReceiver.kt @@ -26,6 +26,7 @@ import com.nextcloud.talk.R import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.data.user.model.User +import com.nextcloud.talk.jobs.ChatMessageCatchUpWorker import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils @@ -121,6 +122,7 @@ class DirectReplyReceiver : BroadcastReceiver() { private fun confirmReplySent() { appendMessageToNotification(replyMessage!!) + ChatMessageCatchUpWorker.enqueue(context, currentUser.id!!, roomToken!!, null) } private fun informReplyFailed() { From 5a1aa8247f818a6703b3c9956b04b07bfc293301 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:17:19 -0400 Subject: [PATCH 66/73] style(auto): wrap microphone permission check Assisted-by: ChatGPT:GPT-5.6-Sol --- .../gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt index e252babda8c..ad9cdcbb609 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/TalkCallsScreen.kt @@ -133,7 +133,10 @@ internal class TalkCallsScreen( } private fun hasMicrophonePermission(): Boolean = - ContextCompat.checkSelfPermission(carContext, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED + ContextCompat.checkSelfPermission( + carContext, + Manifest.permission.RECORD_AUDIO + ) == PackageManager.PERMISSION_GRANTED private fun requestMicrophonePermissionAndStart(conversation: ConversationEntity) { carContext.requestPermissions(listOf(Manifest.permission.RECORD_AUDIO)) { grantedPermissions, _ -> From 3060783ccd9978ea9fcc25c7278e948c9ae07f08 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:23:49 -0400 Subject: [PATCH 67/73] ci(auto): validate final Telecom participant integration Assisted-by: ChatGPT:GPT-5.6-Sol --- ...to-validate-telecom-participants-final.yml | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/android-auto-validate-telecom-participants-final.yml diff --git a/.github/workflows/android-auto-validate-telecom-participants-final.yml b/.github/workflows/android-auto-validate-telecom-participants-final.yml new file mode 100644 index 00000000000..88edc2c335f --- /dev/null +++ b/.github/workflows/android-auto-validate-telecom-participants-final.yml @@ -0,0 +1,94 @@ +name: Android Auto - validate Telecom participants final + +on: + push: + branches: + - android-auto-telecom-participants-final + paths: + - .github/workflows/android-auto-validate-telecom-participants-final.yml + +permissions: + contents: write + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + with: + ref: android-auto-telecom-participants-final + fetch-depth: 0 + + - name: Reuse proven participant patch + shell: bash + run: | + set -euo pipefail + curl -fsSL \ + https://raw.githubusercontent.com/michaave/Nextcloud_Talk_Android_Auto/android-auto-telecom-participants/.github/workflows/android-auto-validate-telecom-participants.yml \ + -o /tmp/participant-validator.yml + python3 - <<'PY' + from pathlib import Path + + workflow = Path('/tmp/participant-validator.yml').read_text() + section = workflow.index(' - name: Apply speaking and participant integration') + start_marker = " python3 - <<'PY'\n" + start = workflow.index(start_marker, section) + len(start_marker) + end = workflow.index(' PY\n', start) + lines = workflow[start:end].splitlines() + script = '\n'.join(line[10:] if line.startswith(' ') else line for line in lines) + '\n' + Path('/tmp/apply-participants.py').write_text(script) + PY + python3 /tmp/apply-participants.py + + - name: Format participant source + run: ./gradlew ktlintFormat --stacktrace + + - name: Verify formatting scope + shell: bash + run: | + set -euo pipefail + cat > /tmp/allowed-files <<'EOF' + app/src/gplay/AndroidManifest.xml + app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt + app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt + app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt + app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt + app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt + app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt + app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java + app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java + app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt + EOF + unexpected="$(git diff --name-only | grep -vxFf /tmp/allowed-files || true)" + if [ -n "$unexpected" ]; then + echo "Unexpected files changed by participant patch/formatting:" + echo "$unexpected" + exit 1 + fi + git diff --check + + - name: Commit validated candidate source + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add app/src/gplay app/src/main app/src/test + git commit -m $'feat(auto): publish call participants to Telecom\n\nAssisted-by: ChatGPT:GPT-5.6-Sol' + + - name: Run speaking notifier tests + run: ./gradlew :app:testGplayDebugUnitTest --tests com.nextcloud.talk.webrtc.DataChannelMessageNotifierTest --stacktrace + + - name: Compile Android Auto flavors + run: ./gradlew :app:compileGplayDebugKotlin :app:compileGenericDebugKotlin --stacktrace + + - name: Run Kotlin style check + run: ./gradlew ktlintCheck --stacktrace + + - name: Push validated source + shell: bash + run: | + set -euo pipefail + git fetch origin android-auto-telecom-participants-final + git rebase origin/android-auto-telecom-participants-final + git push origin HEAD:android-auto-telecom-participants-final From 60b4632aa448c59fa07fc5b26423ede6f75fa2c9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 02:25:55 +0000 Subject: [PATCH 68/73] feat(auto): publish call participants to Telecom Assisted-by: ChatGPT:GPT-5.6-Sol --- app/src/gplay/AndroidManifest.xml | 1 + .../auto/call/TalkTelecomInteropReceiver.kt | 9 ++ .../talk/auto/call/TalkTelecomManager.kt | 99 +++++++++++++------ .../nextcloud/talk/activities/CallActivity.kt | 44 +++++++++ .../talk/activities/ParticipantHandler.kt | 10 +- .../talk/activities/ParticipantUiState.kt | 3 +- .../nextcloud/talk/call/TalkCallInterop.kt | 23 +++++ .../webrtc/DataChannelMessageNotifier.java | 12 +++ .../talk/webrtc/PeerConnectionWrapper.java | 14 +++ .../webrtc/DataChannelMessageNotifierTest.kt | 14 +++ 10 files changed, 198 insertions(+), 31 deletions(-) diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 68e13871e43..bda3387275e 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -55,6 +55,7 @@ + diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt index a270ea55a11..848d4415713 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt @@ -42,6 +42,15 @@ class TalkTelecomInteropReceiver : BroadcastReceiver() { TalkCallInterop.ACTION_CALL_ACTIVE -> manager.onCallActive(callKey) TalkCallInterop.ACTION_CALL_ENDED -> manager.onCallEnded(callKey) + TalkCallInterop.ACTION_CALL_PARTICIPANTS_CHANGED -> { + manager.onParticipantsChanged( + callKey = callKey, + participantIds = intent.getStringArrayExtra(TalkCallInterop.EXTRA_PARTICIPANT_IDS) ?: emptyArray(), + participantNames = + intent.getStringArrayExtra(TalkCallInterop.EXTRA_PARTICIPANT_NAMES) ?: emptyArray(), + activeParticipantId = intent.getStringExtra(TalkCallInterop.EXTRA_ACTIVE_PARTICIPANT_ID) + ) + } TalkCallInterop.ACTION_CONTROL_AUDIO_ENDPOINT -> { manager.requestAudioEndpoint( callKey, diff --git a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt index b67fe36b7a5..0b15291a66c 100644 --- a/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt +++ b/app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt @@ -17,6 +17,8 @@ import androidx.core.telecom.CallAttributesCompat import androidx.core.telecom.CallControlScope import androidx.core.telecom.CallEndpointCompat import androidx.core.telecom.CallsManager +import androidx.core.telecom.extensions.Participant as TelecomParticipant +import androidx.core.telecom.extensions.ParticipantExtension import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.call.TalkCallInterop import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY @@ -110,6 +112,25 @@ class TalkTelecomManager private constructor(context: Context) { } } + fun onParticipantsChanged( + callKey: String, + participantIds: Array, + participantNames: Array, + activeParticipantId: String? + ) { + if (callKey.isBlank() || participantIds.size != participantNames.size) return + val managed = calls[callKey] ?: return + managed.participants = participantIds.zip(participantNames) + .mapNotNull { (id, name) -> + id.takeIf { it.isNotBlank() }?.let { TelecomParticipant(it, name.ifBlank { "Guest" }) } + } + .distinctBy(TelecomParticipant::id) + managed.activeParticipantId = activeParticipantId + if (managed.participantExtension != null) { + scope.launch { publishParticipantState(managed) } + } + } + fun requestAudioEndpoint(callKey: String, route: String) { if (callKey.isBlank() || route.isBlank()) return val managed = calls[callKey] ?: return @@ -200,7 +221,7 @@ class TalkTelecomManager private constructor(context: Context) { callCapabilities = 0 ) - callsManager.addCall( + callsManager.addCallWithExtensions( callAttributes = attributes, onAnswer = { requestedCallType -> managed.answeredByTelecom = true @@ -236,37 +257,45 @@ class TalkTelecomManager private constructor(context: Context) { } } ) { - val callControl = this - managed.control = callControl - - scope.launch { - currentCallEndpoint - .distinctUntilChanged() - .collect { endpoint -> - managed.currentEndpoint = endpoint - publishAudioState(managed) - } - } + val participantExtension = addParticipantExtension( + initialParticipants = managed.participants, + initialActiveParticipant = managed.activeParticipant() + ) + onCall { + val callControl = this + managed.control = callControl + managed.participantExtension = participantExtension + publishParticipantState(managed) + + scope.launch { + currentCallEndpoint + .distinctUntilChanged() + .collect { endpoint -> + managed.currentEndpoint = endpoint + publishAudioState(managed) + } + } - scope.launch { - availableEndpoints - .distinctUntilChanged() - .collect { endpoints -> - managed.availableEndpoints = endpoints - publishAudioState(managed) - } - } + scope.launch { + availableEndpoints + .distinctUntilChanged() + .collect { endpoints -> + managed.availableEndpoints = endpoints + publishAudioState(managed) + } + } - scope.launch { - isMuted - .distinctUntilChanged() - .collect { muted -> - TalkCallInterop.requestMute(appContext, managed.callKey, muted) - } - } + scope.launch { + isMuted + .distinctUntilChanged() + .collect { muted -> + TalkCallInterop.requestMute(appContext, managed.callKey, muted) + } + } - if (managed.activityStarted) { - scope.launch { activateStartedCall(managed, callControl) } + if (managed.activityStarted) { + scope.launch { activateStartedCall(managed, callControl) } + } } } } catch (t: Throwable) { @@ -277,6 +306,12 @@ class TalkTelecomManager private constructor(context: Context) { } } + private suspend fun publishParticipantState(managed: ManagedCall) { + val participantExtension = managed.participantExtension ?: return + participantExtension.updateParticipants(managed.participants) + participantExtension.updateActiveParticipant(managed.activeParticipant()) + } + private fun publishAudioState(managed: ManagedCall) { val currentRoute = managed.currentEndpoint?.let(::routeForEndpoint) val availableRoutes = managed.availableEndpoints @@ -333,10 +368,16 @@ class TalkTelecomManager private constructor(context: Context) { @Volatile var activityStarted: Boolean, @Volatile var answeredByTelecom: Boolean = false, @Volatile var control: CallControlScope? = null, + @Volatile var participantExtension: ParticipantExtension? = null, + @Volatile var participants: List = emptyList(), + @Volatile var activeParticipantId: String? = null, @Volatile var currentEndpoint: CallEndpointCompat? = null, @Volatile var availableEndpoints: List = emptyList() ) + private fun ManagedCall.activeParticipant(): TelecomParticipant? = + participants.firstOrNull { it.id == activeParticipantId } + companion object { private const val TAG = "TalkTelecomManager" diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt index caaa57f0af9..05590342f41 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -54,6 +54,7 @@ import androidx.core.app.NotificationManagerCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.net.toUri import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import autodagger.AutoInjector import com.bluelinelabs.logansquare.LoganSquare import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -164,6 +165,7 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import okhttp3.Cache import org.apache.commons.lang3.StringEscapeUtils @@ -492,6 +494,12 @@ class CallActivity : CallBaseActivity() { ) } + lifecycleScope.launch { + callViewModel.participants.collectLatest { participants -> + publishTelecomParticipants(participants) + } + } + credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token) if (TextUtils.isEmpty(baseUrl)) { baseUrl = conversationUser!!.baseUrl @@ -514,6 +522,42 @@ class CallActivity : CallBaseActivity() { checkInitialDevicePermissions() } + private fun publishTelecomParticipants(participants: List) { + if (!::conversationUser.isInitialized) return + val accountId = conversationUser.id ?: return + val token = roomToken?.takeIf { it.isNotBlank() } ?: return + val connectedParticipants = participants + .filter { it.isConnected && !it.sessionKey.isNullOrBlank() } + .sortedBy { it.sessionKey } + + val participantIds = mutableListOf("self:$accountId") + val participantNames = mutableListOf( + conversationUser.displayName?.takeIf { it.isNotBlank() } + ?: conversationUser.username?.takeIf { it.isNotBlank() } + ?: "You" + ) + + connectedParticipants.forEach { participant -> + val sessionId = participant.sessionKey ?: return@forEach + participantIds.add("session:$sessionId") + participantNames.add(participant.nick?.takeIf { it.isNotBlank() } ?: "Guest") + } + + val activeParticipantId = connectedParticipants + .firstOrNull { it.isSpeaking } + ?.sessionKey + ?.let { "session:$it" } + + TalkCallInterop.notifyCallParticipants( + context = this, + accountId = accountId, + roomToken = token, + participantIds = participantIds.toTypedArray(), + participantNames = participantNames.toTypedArray(), + activeParticipantId = activeParticipantId + ) + } + private fun registerTelecomControlReceiver() { if (telecomControlReceiverRegistered) return val filter = IntentFilter().apply { diff --git a/app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt b/app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt index ce7ad3dde75..27af9110592 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt @@ -145,7 +145,15 @@ class ParticipantHandler( override fun onAudioOff() { Log.d(TAG, "onAudioOff: ${_uiState.value.nick} (sessionId=${_uiState.value.sessionKey})") - _uiState.update { it.copy(isAudioEnabled = false) } + _uiState.update { it.copy(isAudioEnabled = false, isSpeaking = false) } + } + + override fun onSpeaking() { + _uiState.update { it.copy(isSpeaking = true) } + } + + override fun onStoppedSpeaking() { + _uiState.update { it.copy(isSpeaking = false) } } override fun onVideoOn() { diff --git a/app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt b/app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt index eed0e0e812c..8e41d0a886f 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt @@ -24,5 +24,6 @@ data class ParticipantUiState( val raisedHand: Boolean, val actorType: Participant.ActorType? = null, val actorId: String? = null, - val isInternal: Boolean + val isInternal: Boolean, + val isSpeaking: Boolean = false ) diff --git a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt index 413bc24f1f4..d26c40da30b 100644 --- a/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt +++ b/app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt @@ -25,6 +25,7 @@ object TalkCallInterop { const val ACTION_CALL_STARTED = "com.nextcloud.talk.call.action.STARTED" const val ACTION_CALL_ACTIVE = "com.nextcloud.talk.call.action.ACTIVE" const val ACTION_CALL_ENDED = "com.nextcloud.talk.call.action.ENDED" + const val ACTION_CALL_PARTICIPANTS_CHANGED = "com.nextcloud.talk.call.action.PARTICIPANTS_CHANGED" const val ACTION_CONTROL_DISCONNECT = "com.nextcloud.talk.call.action.CONTROL_DISCONNECT" const val ACTION_CONTROL_MUTE = "com.nextcloud.talk.call.action.CONTROL_MUTE" @@ -44,6 +45,9 @@ object TalkCallInterop { const val EXTRA_VIDEO = "talk_video" const val EXTRA_MUTED = "talk_muted" const val EXTRA_AUDIO_ROUTE = "talk_audio_route" + const val EXTRA_PARTICIPANT_IDS = "talk_participant_ids" + const val EXTRA_PARTICIPANT_NAMES = "talk_participant_names" + const val EXTRA_ACTIVE_PARTICIPANT_ID = "talk_active_participant_id" @Volatile private var activeTelecomCallKey: String? = null @@ -105,6 +109,25 @@ object TalkCallInterop { notifySimple(context, ACTION_CALL_ENDED, accountId, roomToken) } + fun notifyCallParticipants( + context: Context, + accountId: Long, + roomToken: String, + participantIds: Array, + participantNames: Array, + activeParticipantId: String? + ) { + if (accountId < 0L || roomToken.isBlank() || participantIds.size != participantNames.size) return + val intent = Intent(ACTION_CALL_PARTICIPANTS_CHANGED) + .putExtra(EXTRA_CALL_KEY, callKey(accountId, roomToken)) + .putExtra(EXTRA_PARTICIPANT_IDS, participantIds) + .putExtra(EXTRA_PARTICIPANT_NAMES, participantNames) + if (!activeParticipantId.isNullOrBlank()) { + intent.putExtra(EXTRA_ACTIVE_PARTICIPANT_ID, activeParticipantId) + } + send(context, intent) + } + fun requestDisconnect(context: Context, callKey: String) { send(context, Intent(ACTION_CONTROL_DISCONNECT).putExtra(EXTRA_CALL_KEY, callKey)) } diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java b/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java index 2fca22ac8ff..83fd74b64ab 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java @@ -45,6 +45,18 @@ public synchronized void notifyAudioOff() { } } + public synchronized void notifySpeaking() { + for (PeerConnectionWrapper.DataChannelMessageListener listener : new ArrayList<>(dataChannelMessageListeners)) { + listener.onSpeaking(); + } + } + + public synchronized void notifyStoppedSpeaking() { + for (PeerConnectionWrapper.DataChannelMessageListener listener : new ArrayList<>(dataChannelMessageListeners)) { + listener.onStoppedSpeaking(); + } + } + public synchronized void notifyVideoOn() { for (PeerConnectionWrapper.DataChannelMessageListener listener : new ArrayList<>(dataChannelMessageListeners)) { listener.onVideoOn(); diff --git a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java index 484ad344607..7436cd1da6e 100644 --- a/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java +++ b/app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java @@ -83,6 +83,8 @@ public class PeerConnectionWrapper { public interface DataChannelMessageListener { void onAudioOn(); void onAudioOff(); + void onSpeaking(); + void onStoppedSpeaking(); void onVideoOn(); void onVideoOff(); void onNickChanged(String nick); @@ -517,6 +519,18 @@ public void onMessage(DataChannel.Buffer buffer) { return; } + if ("speaking".equals(dataChannelMessage.getType())) { + dataChannelMessageNotifier.notifySpeaking(); + + return; + } + + if ("stoppedSpeaking".equals(dataChannelMessage.getType())) { + dataChannelMessageNotifier.notifyStoppedSpeaking(); + + return; + } + if ("videoOn".equals(dataChannelMessage.getType())) { dataChannelMessageNotifier.notifyVideoOn(); diff --git a/app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt b/app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt index ead358b6ec6..90f23948f96 100644 --- a/app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt +++ b/app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt @@ -51,6 +51,20 @@ class DataChannelMessageNotifierTest { verify(listener).onAudioOff() } + @Test + fun testNotifySpeaking() { + notifier.addListener(listener) + notifier.notifySpeaking() + verify(listener).onSpeaking() + } + + @Test + fun testNotifyStoppedSpeaking() { + notifier.addListener(listener) + notifier.notifyStoppedSpeaking() + verify(listener).onStoppedSpeaking() + } + @Test fun testNotifyVideoOn() { notifier.addListener(listener) From 33d80b9ec7e9baa5c424674d76af0ccceba6932f Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:43:54 -0400 Subject: [PATCH 69/73] ci(auto): remove completed participant validator Assisted-by: ChatGPT:GPT-5.6-Sol --- ...to-validate-telecom-participants-final.yml | 94 ------------------- 1 file changed, 94 deletions(-) delete mode 100644 .github/workflows/android-auto-validate-telecom-participants-final.yml diff --git a/.github/workflows/android-auto-validate-telecom-participants-final.yml b/.github/workflows/android-auto-validate-telecom-participants-final.yml deleted file mode 100644 index 88edc2c335f..00000000000 --- a/.github/workflows/android-auto-validate-telecom-participants-final.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Android Auto - validate Telecom participants final - -on: - push: - branches: - - android-auto-telecom-participants-final - paths: - - .github/workflows/android-auto-validate-telecom-participants-final.yml - -permissions: - contents: write - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: android-auto-telecom-participants-final - fetch-depth: 0 - - - name: Reuse proven participant patch - shell: bash - run: | - set -euo pipefail - curl -fsSL \ - https://raw.githubusercontent.com/michaave/Nextcloud_Talk_Android_Auto/android-auto-telecom-participants/.github/workflows/android-auto-validate-telecom-participants.yml \ - -o /tmp/participant-validator.yml - python3 - <<'PY' - from pathlib import Path - - workflow = Path('/tmp/participant-validator.yml').read_text() - section = workflow.index(' - name: Apply speaking and participant integration') - start_marker = " python3 - <<'PY'\n" - start = workflow.index(start_marker, section) + len(start_marker) - end = workflow.index(' PY\n', start) - lines = workflow[start:end].splitlines() - script = '\n'.join(line[10:] if line.startswith(' ') else line for line in lines) + '\n' - Path('/tmp/apply-participants.py').write_text(script) - PY - python3 /tmp/apply-participants.py - - - name: Format participant source - run: ./gradlew ktlintFormat --stacktrace - - - name: Verify formatting scope - shell: bash - run: | - set -euo pipefail - cat > /tmp/allowed-files <<'EOF' - app/src/gplay/AndroidManifest.xml - app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomInteropReceiver.kt - app/src/gplay/java/com/nextcloud/talk/auto/call/TalkTelecomManager.kt - app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt - app/src/main/java/com/nextcloud/talk/activities/ParticipantHandler.kt - app/src/main/java/com/nextcloud/talk/activities/ParticipantUiState.kt - app/src/main/java/com/nextcloud/talk/call/TalkCallInterop.kt - app/src/main/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifier.java - app/src/main/java/com/nextcloud/talk/webrtc/PeerConnectionWrapper.java - app/src/test/java/com/nextcloud/talk/webrtc/DataChannelMessageNotifierTest.kt - EOF - unexpected="$(git diff --name-only | grep -vxFf /tmp/allowed-files || true)" - if [ -n "$unexpected" ]; then - echo "Unexpected files changed by participant patch/formatting:" - echo "$unexpected" - exit 1 - fi - git diff --check - - - name: Commit validated candidate source - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add app/src/gplay app/src/main app/src/test - git commit -m $'feat(auto): publish call participants to Telecom\n\nAssisted-by: ChatGPT:GPT-5.6-Sol' - - - name: Run speaking notifier tests - run: ./gradlew :app:testGplayDebugUnitTest --tests com.nextcloud.talk.webrtc.DataChannelMessageNotifierTest --stacktrace - - - name: Compile Android Auto flavors - run: ./gradlew :app:compileGplayDebugKotlin :app:compileGenericDebugKotlin --stacktrace - - - name: Run Kotlin style check - run: ./gradlew ktlintCheck --stacktrace - - - name: Push validated source - shell: bash - run: | - set -euo pipefail - git fetch origin android-auto-telecom-participants-final - git rebase origin/android-auto-telecom-participants-final - git push origin HEAD:android-auto-telecom-participants-final From 635a14f833efc3945699b70eb3f6275ad884d001 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 22:44:41 -0400 Subject: [PATCH 70/73] ci(auto): publish GPlay debug APK artifact Assisted-by: ChatGPT:GPT-5.6-Sol --- .github/workflows/android-auto-apk.yml | 59 ++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .github/workflows/android-auto-apk.yml diff --git a/.github/workflows/android-auto-apk.yml b/.github/workflows/android-auto-apk.yml new file mode 100644 index 00000000000..8472f89488f --- /dev/null +++ b/.github/workflows/android-auto-apk.yml @@ -0,0 +1,59 @@ +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 GPlay debug APK + run: ./gradlew --no-daemon :app:assembleGplayDebug --stacktrace + + - name: Verify APK output + shell: bash + run: | + set -euo pipefail + shopt -s nullglob + apks=(app/build/outputs/apk/gplay/debug/*.apk) + if [ ${#apks[@]} -eq 0 ]; then + echo "No GPlay debug APK was produced" + exit 1 + fi + printf 'Built APK: %s\n' "${apks[@]}" + + - name: Upload Android Auto APK + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: Nextcloud-Talk-Android-Auto-Gplay-Debug + path: app/build/outputs/apk/gplay/debug/*.apk + if-no-files-found: error + retention-days: 14 From d8af4062788fc76da10388b7ff72726cc04f4c1a Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 23:22:57 -0400 Subject: [PATCH 71/73] build(auto): add opt-in side-by-side package Normal debug builds retain com.nextcloud.talk2. Passing -PandroidAutoSideBySide=true produces com.nextcloud.talk2.auto with an -auto version suffix. Validated with normal GPlay + generic compilation, side-by-side GPlay APK assembly, exact application ID metadata, and ktlint. Assisted-by: ChatGPT:GPT-5.6-Sol --- app/build.gradle.kts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a861ffc8588..d4e78c672de 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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" @@ -110,6 +113,13 @@ android { } buildTypes { + getByName("debug") { + if (androidAutoSideBySide) { + applicationIdSuffix = ".auto" + versionNameSuffix = "-auto" + } + } + release { isMinifyEnabled = false proguardFiles( From c240dda19608fa0cfbcd6bb80014a0e6eccf4998 Mon Sep 17 00:00:00 2001 From: michaave Date: Mon, 24 Aug 2026 23:23:28 -0400 Subject: [PATCH 72/73] ci(auto): publish standard and side-by-side APKs Verify each application ID, stage deterministic filenames, and include SHA-256 checksums. Assisted-by: ChatGPT:GPT-5.6-Sol --- .github/workflows/android-auto-apk.yml | 96 ++++++++++++++++++++++---- 1 file changed, 84 insertions(+), 12 deletions(-) diff --git a/.github/workflows/android-auto-apk.yml b/.github/workflows/android-auto-apk.yml index 8472f89488f..2a5f6ad6ec0 100644 --- a/.github/workflows/android-auto-apk.yml +++ b/.github/workflows/android-auto-apk.yml @@ -35,25 +35,97 @@ jobs: - name: Validate Gradle wrapper uses: gradle/actions/wrapper-validation@v5 - - name: Assemble GPlay debug APK + - name: Assemble standard GPlay debug APK run: ./gradlew --no-daemon :app:assembleGplayDebug --stacktrace - - name: Verify APK output + - name: Stage standard APK shell: bash run: | set -euo pipefail - shopt -s nullglob - apks=(app/build/outputs/apk/gplay/debug/*.apk) - if [ ${#apks[@]} -eq 0 ]; then - echo "No GPlay debug APK was produced" - exit 1 - fi - printf 'Built APK: %s\n' "${apks[@]}" - - - name: Upload Android Auto APK + 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: app/build/outputs/apk/gplay/debug/*.apk + 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 From 20e61ab18fbc49bd9089eaf63a45f426613b89a0 Mon Sep 17 00:00:00 2001 From: michaave Date: Tue, 25 Aug 2026 00:41:21 -0400 Subject: [PATCH 73/73] fix(auto): declare Car App template capability Assisted-by: ChatGPT:GPT-5.6-Sol --- app/src/main/res/xml/automotive_app_desc.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml index 3082aa4c1ed..558e61c01bc 100644 --- a/app/src/main/res/xml/automotive_app_desc.xml +++ b/app/src/main/res/xml/automotive_app_desc.xml @@ -8,4 +8,5 @@ - \ No newline at end of file + +