From d2e52cebf4817977e33826303e1ea7f652dfefcf Mon Sep 17 00:00:00 2001 From: natarajkr Date: Wed, 28 Jan 2026 22:58:31 +0530 Subject: [PATCH 1/4] Update core-telecom dependency and add CALL_BACK intent filter - Update `androidx.core:core-telecom` from `1.0.0-alpha02` to `1.0.1` (latest stable). - Add `android.telecom.action.CALL_BACK` intent filter to the main activity to support integrated call logging. --- samples/connectivity/telecom/build.gradle.kts | 2 +- .../connectivity/telecom/src/main/AndroidManifest.xml | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/samples/connectivity/telecom/build.gradle.kts b/samples/connectivity/telecom/build.gradle.kts index efa9277a..36c609c1 100644 --- a/samples/connectivity/telecom/build.gradle.kts +++ b/samples/connectivity/telecom/build.gradle.kts @@ -39,7 +39,7 @@ android { } dependencies { - implementation("androidx.core:core-telecom:1.0.0-alpha02") + implementation("androidx.core:core-telecom:1.0.1") implementation(project(mapOf("path" to ":samples:connectivity:audio"))) implementation(libs.androidx.activity.compose) diff --git a/samples/connectivity/telecom/src/main/AndroidManifest.xml b/samples/connectivity/telecom/src/main/AndroidManifest.xml index 8b308fe4..51d9a7f3 100644 --- a/samples/connectivity/telecom/src/main/AndroidManifest.xml +++ b/samples/connectivity/telecom/src/main/AndroidManifest.xml @@ -20,7 +20,14 @@ android:showOnLockScreen="true" android:showWhenLocked="true" android:turnScreenOn="true" - tools:targetApi="o" /> + tools:targetApi="o"> + + + + + + + Date: Mon, 6 Apr 2026 20:55:35 +0530 Subject: [PATCH 2/4] Update Telecom sample with call log exclusion and callback support - Update: `androidx.core:core-telecom` to `1.1.0-alpha04`. - Add: a UI option to the Telecom sample to exclude calls from the system call log using the `isLogExcluded` property in `CallAttributesCompat`. - Implement handling for `TelecomManager.ACTION_CALL_BACK` in `TelecomCallActivity` to support re-initiating calls from the system UI. - Update Android Gradle Plugin to `8.13.2` and Gradle wrapper to `8.13` to compile against 36.1. - Refactor URI creation to use the `toUri()` extension function. - Update `compileSdk` configuration and add the Foojay toolchain resolver plugin. --- gradle/libs.versions.toml | 4 ++- gradle/wrapper/gradle-wrapper.properties | 2 +- samples/connectivity/telecom/build.gradle.kts | 11 +++++-- .../connectivity/telecom/TelecomCallSample.kt | 30 +++++++++++++++++-- .../telecom/call/TelecomCallActivity.kt | 18 +++++++++-- .../telecom/call/TelecomCallService.kt | 4 ++- .../telecom/model/TelecomCallRepository.kt | 17 ++++++----- settings.gradle.kts | 3 ++ 8 files changed, 71 insertions(+), 18 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5a6918f1..f6e23bab 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,7 +14,7 @@ # limitations under the License. # [versions] -agp = "8.9.1" +agp = "8.13.2" fragmentCompose = "1.8.6" kotlin = "2.1.10" coreKtx = "1.17.0" @@ -66,6 +66,7 @@ playServicesMlkitBarcodeScanning = "18.3.1" protobuf = "0.9.4" firebaseCrashlyticsBuildtools = "3.0.5" uwb = "1.0.0-alpha10" +telecom = "1.1.0-alpha04" [libraries] @@ -99,6 +100,7 @@ coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coil" } coil-video = { module = "io.coil-kt:coil-video", version.ref = "coil" } kotlin-coroutines-play = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "coroutines" } play-services-location = { module = "com.google.android.gms:play-services-location", version.ref = "play-services-location" } +androidx-core-telecom = { module = "androidx.core:core-telecom", version.ref = "telecom" } # Core dependencies android-gradlePlugin = { module = "com.android.tools.build:gradle", version.ref = "agp" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e2847c82..37f853b1 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/samples/connectivity/telecom/build.gradle.kts b/samples/connectivity/telecom/build.gradle.kts index 098e282e..a198e264 100644 --- a/samples/connectivity/telecom/build.gradle.kts +++ b/samples/connectivity/telecom/build.gradle.kts @@ -25,11 +25,14 @@ plugins { android { namespace = "com.example.platform.connectivity.telecom" - compileSdk = 36 + compileSdk { + version = release(version = 36) { + minorApiLevel = 1 + } + } defaultConfig { minSdk = 23 - targetSdk = 35 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } @@ -39,7 +42,6 @@ android { } dependencies { - implementation("androidx.core:core-telecom:1.0.1") implementation(project(mapOf("path" to ":samples:connectivity:audio"))) implementation(libs.androidx.activity.compose) @@ -50,6 +52,9 @@ dependencies { implementation(libs.androidx.material3) implementation(project(":shared")) + // Sample specific dependencies + implementation(libs.androidx.core.telecom) + implementation(libs.accompanist.permissions) androidTestImplementation(libs.androidx.test.core) diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt index ccd50a6b..0a030a7f 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt @@ -25,16 +25,21 @@ import android.widget.Toast import androidx.annotation.RequiresApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material3.Button +import androidx.compose.material3.Checkbox import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -44,6 +49,7 @@ import com.example.platform.connectivity.telecom.call.TelecomCallService import com.example.platform.connectivity.telecom.model.TelecomCall import com.example.platform.connectivity.telecom.model.TelecomCallRepository import com.example.platform.shared.PermissionBox +import androidx.core.net.toUri @RequiresApi(Build.VERSION_CODES.O) @Composable @@ -104,6 +110,21 @@ private fun TelecomCallOptions() { "No active call" } Text(text = title, style = MaterialTheme.typography.titleLarge) + + var excludeCallLogging by rememberSaveable { + mutableStateOf(false) + } + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Checkbox( + checked = excludeCallLogging, + onCheckedChange = { isChecked -> + excludeCallLogging = isChecked + } + ) + Text("Exclude from call logs") + } Button( enabled = !hasOngoingCall, onClick = { @@ -111,7 +132,8 @@ private fun TelecomCallOptions() { context.launchCall( action = TelecomCallService.ACTION_INCOMING_CALL, name = "Alice", - uri = Uri.parse("tel:12345"), + uri = "tel:12345".toUri(), + excludeCallLogging ) }, ) { @@ -123,7 +145,8 @@ private fun TelecomCallOptions() { context.launchCall( action = TelecomCallService.ACTION_OUTGOING_CALL, name = "Bob", - uri = Uri.parse("tel:54321"), + uri = "tel:54321".toUri(), + excludeCallLogging ) }, ) { @@ -133,12 +156,13 @@ private fun TelecomCallOptions() { } @RequiresApi(Build.VERSION_CODES.O) -private fun Context.launchCall(action: String, name: String, uri: Uri) { +internal fun Context.launchCall(action: String, name: String, uri: Uri, excludeCallLogging: Boolean) { startService( Intent(this, TelecomCallService::class.java).apply { this.action = action putExtra(TelecomCallService.EXTRA_NAME, name) putExtra(TelecomCallService.EXTRA_URI, uri) + putExtra(TelecomCallService.EXTRA_EXCLUDE_CALL_LOGGING, excludeCallLogging) }, ) } diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt index 0da07851..5c74b819 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt @@ -20,6 +20,7 @@ import android.app.KeyguardManager import android.content.Intent import android.os.Build import android.os.Bundle +import android.telecom.TelecomManager import android.util.Log import android.view.WindowManager import androidx.activity.ComponentActivity @@ -31,6 +32,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.ui.Modifier import androidx.core.content.getSystemService +import androidx.core.net.toUri +import com.example.platform.connectivity.telecom.launchCall import com.example.platform.connectivity.telecom.model.TelecomCallRepository @@ -50,6 +53,8 @@ class TelecomCallActivity : ComponentActivity() { // Set the right flags for a call type activity. setupCallActivity() + handleCallBack() + setContent { MaterialTheme { Surface( @@ -94,8 +99,17 @@ class TelecomCallActivity : ComponentActivity() { } val keyguardManager = getSystemService() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && keyguardManager != null) { - keyguardManager.requestDismissKeyguard(this, null) + keyguardManager?.requestDismissKeyguard(this, null) + } + + private fun handleCallBack() { + if (intent.action == TelecomManager.ACTION_CALL_BACK) { + launchCall( + action = TelecomCallService.ACTION_OUTGOING_CALL, + name = "Bob", + uri = "tel:54321".toUri(), + false + ) } } } diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallService.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallService.kt index d894c467..cd2a311f 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallService.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallService.kt @@ -59,6 +59,7 @@ class TelecomCallService : Service() { companion object { internal const val EXTRA_NAME: String = "extra_name" internal const val EXTRA_URI: String = "extra_uri" + internal const val EXTRA_EXCLUDE_CALL_LOGGING = "extra_exclude_call_logging" internal const val ACTION_INCOMING_CALL = "incoming_call" internal const val ACTION_OUTGOING_CALL = "outgoing_call" internal const val ACTION_UPDATE_CALL = "update_call" @@ -124,6 +125,7 @@ class TelecomCallService : Service() { @Suppress("DEPRECATION") intent.getParcelableExtra(EXTRA_URI)!! } + val excludeCallLogging = intent.getBooleanExtra(EXTRA_EXCLUDE_CALL_LOGGING, false) scope.launch { if (incoming) { @@ -133,7 +135,7 @@ class TelecomCallService : Service() { launch { // Register the call with the Telecom stack - telecomRepository.registerCall(name, uri, incoming) + telecomRepository.registerCall(name, uri, excludeCallLogging, incoming) } if (!incoming) { diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt index 8c56e715..a1740a6f 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt @@ -25,11 +25,7 @@ import androidx.annotation.RequiresApi import androidx.core.telecom.CallAttributesCompat import androidx.core.telecom.CallControlResult import androidx.core.telecom.CallControlScope -import androidx.core.telecom.CallException import androidx.core.telecom.CallsManager -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow @@ -87,16 +83,23 @@ class TelecomCallRepository(private val callsManager: CallsManager) { * Register a new call with the provided attributes. * Use the [currentCall] StateFlow to receive status updates and process call related actions. */ - suspend fun registerCall(displayName: String, address: Uri, isIncoming: Boolean) { - // For simplicity we don't support multiple calls + suspend fun registerCall( + displayName: String, + address: Uri, + excludeCallLogging: Boolean, + isIncoming: Boolean + ) { + // For simplicity, we don't support multiple calls check(_currentCall.value !is TelecomCall.Registered) { "There cannot be more than one call at the same time." } // Create the call attributes + /* TODO (add isLogExcluded param for showcase) */ val attributes = CallAttributesCompat( displayName = displayName, address = address, + isLogExcluded = excludeCallLogging, direction = if (isIncoming) { CallAttributesCompat.DIRECTION_INCOMING } else { @@ -221,7 +224,7 @@ class TelecomCallRepository(private val callsManager: CallsManager) { } is TelecomCallAction.ToggleMute -> { - // We cannot programmatically mute the telecom stack. Instead we just update + // We cannot programmatically mute the telecom stack. Instead, we just update // the state of the call and this will start/stop audio capturing. updateCurrentCall { copy(isMuted = !isMuted) diff --git a/settings.gradle.kts b/settings.gradle.kts index 76de2e01..af8fc634 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,6 +27,9 @@ pluginManagement { gradlePluginPortal() } } +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.10.0" +} dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { From 5e841736dcacc1d37ff6c5dd08da789813e94580 Mon Sep 17 00:00:00 2001 From: natarajkr Date: Tue, 7 Apr 2026 14:46:33 +0530 Subject: [PATCH 3/4] Update Telecom call handling and WindowManager initialization - Add `onNewIntent` to `TelecomCallActivity` to handle call-back intents when the activity is already running. - Remove obsolete TODO regarding `isLogExcluded` in `TelecomCallRepository`. - Add `@SuppressLint("RequiresWindowSdk")` to `ExampleWindowInitializer.create` to suppress false positive lint warning. Change-Id: I66df7227042f72d20cd328cac16a8a802385781b --- .../connectivity/telecom/call/TelecomCallActivity.kt | 6 ++++++ .../connectivity/telecom/model/TelecomCallRepository.kt | 1 - .../ui/windowmanager/embedding/ExampleWindowInitializer.kt | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt index 5c74b819..0f202e02 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt @@ -83,6 +83,12 @@ class TelecomCallActivity : ComponentActivity() { ) } + override fun onNewIntent(intent: Intent) { + super.onNewIntent(intent) + setIntent(intent) + handleCallBack() + } + /** * Enable the calling activity to be shown in the lockscreen and dismiss the keyguard to enable * users to answer without unblocking. diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt index a1740a6f..350cc3b7 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/model/TelecomCallRepository.kt @@ -95,7 +95,6 @@ class TelecomCallRepository(private val callsManager: CallsManager) { } // Create the call attributes - /* TODO (add isLogExcluded param for showcase) */ val attributes = CallAttributesCompat( displayName = displayName, address = address, diff --git a/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt b/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt index fa6247a0..8c192828 100644 --- a/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt +++ b/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt @@ -15,6 +15,7 @@ */ package com.example.platform.ui.windowmanager.embedding +import android.annotation.SuppressLint import android.content.Context import androidx.startup.Initializer import androidx.window.WindowSdkExtensions @@ -53,6 +54,7 @@ class ExampleWindowInitializer : Initializer { private val mDemoActivityEmbeddingController = DemoActivityEmbeddingController.getInstance() + @SuppressLint("RequiresWindowSdk") override fun create(context: Context): RuleController { SplitController.getInstance(context).apply { if (WindowSdkExtensions.getInstance().extensionVersion >= 2) { From 7580e85d3ec2023e368c9af8e4cfb305b97cd5b6 Mon Sep 17 00:00:00 2001 From: natarajkr Date: Wed, 8 Apr 2026 22:55:09 +0530 Subject: [PATCH 4/4] Refactor telecom sample parameters and clean up WindowManager initializer - Update `launchCall` invocations to use named arguments for `excludeCallLogging` to improve readability. - moved `@SuppressLint("RequiresWindowSdk")` annotation in `ExampleWindowInitializer` to a new PR. Change-Id: I9e363e3c3b38ef6c840f23fe4b27df5c5d4a9d94 --- .../platform/connectivity/telecom/TelecomCallSample.kt | 4 ++-- .../platform/connectivity/telecom/call/TelecomCallActivity.kt | 2 +- .../ui/windowmanager/embedding/ExampleWindowInitializer.kt | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt index 0a030a7f..30b3e94c 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/TelecomCallSample.kt @@ -133,7 +133,7 @@ private fun TelecomCallOptions() { action = TelecomCallService.ACTION_INCOMING_CALL, name = "Alice", uri = "tel:12345".toUri(), - excludeCallLogging + excludeCallLogging = excludeCallLogging ) }, ) { @@ -146,7 +146,7 @@ private fun TelecomCallOptions() { action = TelecomCallService.ACTION_OUTGOING_CALL, name = "Bob", uri = "tel:54321".toUri(), - excludeCallLogging + excludeCallLogging = excludeCallLogging ) }, ) { diff --git a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt index 0f202e02..abfb6c58 100644 --- a/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt +++ b/samples/connectivity/telecom/src/main/java/com/example/platform/connectivity/telecom/call/TelecomCallActivity.kt @@ -114,7 +114,7 @@ class TelecomCallActivity : ComponentActivity() { action = TelecomCallService.ACTION_OUTGOING_CALL, name = "Bob", uri = "tel:54321".toUri(), - false + excludeCallLogging = false ) } } diff --git a/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt b/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt index 8c192828..fa6247a0 100644 --- a/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt +++ b/samples/user-interface/windowmanager/src/main/java/com/example/platform/ui/windowmanager/embedding/ExampleWindowInitializer.kt @@ -15,7 +15,6 @@ */ package com.example.platform.ui.windowmanager.embedding -import android.annotation.SuppressLint import android.content.Context import androidx.startup.Initializer import androidx.window.WindowSdkExtensions @@ -54,7 +53,6 @@ class ExampleWindowInitializer : Initializer { private val mDemoActivityEmbeddingController = DemoActivityEmbeddingController.getInstance() - @SuppressLint("RequiresWindowSdk") override fun create(context: Context): RuleController { SplitController.getInstance(context).apply { if (WindowSdkExtensions.getInstance().extensionVersion >= 2) {