[go: nahoru, domu]

add a managed connection service to core-telecom

The jetpack package needs a managed service to simulate sim calls for
tests.

Test: 1 unit test
Bug: 285013818

Change-Id: I91dad128bda47370841937b5cfcddb8cb6107362
diff --git a/core/core-telecom/src/androidTest/AndroidManifest.xml b/core/core-telecom/src/androidTest/AndroidManifest.xml
index ec9a3d9..6e24bd3 100644
--- a/core/core-telecom/src/androidTest/AndroidManifest.xml
+++ b/core/core-telecom/src/androidTest/AndroidManifest.xml
@@ -27,7 +27,17 @@
             </intent-filter>
         </service>
 
-        <service android:name="androidx.core.telecom.utils.MockInCallService"
+        <!-- This CS is needed to simulate managed/sim calls for testing -->
+        <service
+            android:name="androidx.core.telecom.test.utils.ManagedConnectionService"
+            android:exported="true"
+            android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
+            <intent-filter>
+                <action android:name="android.telecom.ConnectionService"/>
+            </intent-filter>
+        </service>
+
+        <service android:name="androidx.core.telecom.test.utils.MockInCallService"
             android:permission="android.permission.BIND_INCALL_SERVICE"
             android:exported="true">
             <intent-filter>
@@ -43,7 +53,7 @@
                 android:value="true" />
         </service>
 
-        <activity android:name="androidx.core.telecom.utils.MockDialerActivity"
+        <activity android:name="androidx.core.telecom.test.utils.MockDialerActivity"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.DIAL" />
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlCallbacksTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
similarity index 99%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlCallbacksTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
index 0fcc48c..f1fff4d 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlCallbacksTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlCallbacksTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.os.Build.VERSION_CODES
 import android.telecom.Call
@@ -22,8 +22,8 @@
 import android.telecom.DisconnectCause
 import androidx.annotation.RequiresApi
 import androidx.core.telecom.internal.utils.Utils
-import androidx.core.telecom.utils.BaseTelecomTest
-import androidx.core.telecom.utils.TestUtils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlsTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
similarity index 97%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlsTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
index b9ddb69..5992045 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/BasicCallControlsTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/BasicCallControlsTest.kt
@@ -14,15 +14,18 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.os.Build.VERSION_CODES
 import android.telecom.DisconnectCause
 import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
+import androidx.core.telecom.CallEndpointCompat
+import androidx.core.telecom.CallException
 import androidx.core.telecom.internal.utils.Utils
-import androidx.core.telecom.utils.BaseTelecomTest
-import androidx.core.telecom.utils.MockInCallService
-import androidx.core.telecom.utils.TestUtils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.MockInCallService
+import androidx.core.telecom.test.utils.TestUtils
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/CallEndpointCompatTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallEndpointCompatTest.kt
similarity index 97%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/CallEndpointCompatTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallEndpointCompatTest.kt
index 4a555eb..edc806f 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/CallEndpointCompatTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallEndpointCompatTest.kt
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.os.Build.VERSION_CODES
 import android.os.ParcelUuid
 import android.telecom.CallAudioState
 import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallEndpointCompat
 import androidx.core.telecom.internal.utils.EndpointUtils
 import androidx.test.filters.SdkSuppress
 import java.util.UUID
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/CallsManagerTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallsManagerTest.kt
similarity index 94%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/CallsManagerTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallsManagerTest.kt
index 9b0dfb9..a575a9b 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/CallsManagerTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/CallsManagerTest.kt
@@ -14,15 +14,16 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.os.Build.VERSION_CODES
 import android.telecom.PhoneAccount.CAPABILITY_SELF_MANAGED
 import android.telecom.PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS
 import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallsManager
 import androidx.core.telecom.internal.utils.Utils
-import androidx.core.telecom.utils.BaseTelecomTest
-import androidx.core.telecom.utils.TestUtils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/InCallAudioTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
similarity index 97%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/InCallAudioTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
index 44db0ce..453ec4d 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/InCallAudioTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/InCallAudioTest.kt
@@ -14,15 +14,15 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.media.AudioManager.MODE_IN_COMMUNICATION
 import android.os.Build
 import android.telecom.DisconnectCause
 import androidx.annotation.RequiresApi
 import androidx.core.telecom.internal.utils.Utils
-import androidx.core.telecom.utils.BaseTelecomTest
-import androidx.core.telecom.utils.TestUtils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/JetpackConnectionServiceTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/JetpackConnectionServiceTest.kt
similarity index 93%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/JetpackConnectionServiceTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/JetpackConnectionServiceTest.kt
index 086bf3f..ab14abf 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/JetpackConnectionServiceTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/JetpackConnectionServiceTest.kt
@@ -14,19 +14,20 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom
+package androidx.core.telecom.test
 
 import android.os.Build.VERSION_CODES
 import android.telecom.Connection
 import android.telecom.ConnectionRequest
 import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
 import androidx.core.telecom.internal.CallChannels
 import androidx.core.telecom.internal.JetpackConnectionService
 import androidx.core.telecom.internal.utils.Utils
-import androidx.core.telecom.utils.BaseTelecomTest
-import androidx.core.telecom.utils.TestUtils
-import androidx.core.telecom.utils.TestUtils.TEST_CALL_ATTRIB_NAME
-import androidx.core.telecom.utils.TestUtils.TEST_PHONE_NUMBER_9001
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.TestUtils
+import androidx.core.telecom.test.utils.TestUtils.TEST_CALL_ATTRIB_NAME
+import androidx.core.telecom.test.utils.TestUtils.TEST_PHONE_NUMBER_9001
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SdkSuppress
 import androidx.test.filters.SmallTest
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/ManagedCallsTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/ManagedCallsTest.kt
new file mode 100644
index 0000000..90e8504
--- /dev/null
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/ManagedCallsTest.kt
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.test
+
+import android.content.ComponentName
+import android.net.Uri
+import android.os.Build
+import android.telecom.DisconnectCause
+import android.telecom.PhoneAccount
+import android.telecom.PhoneAccountHandle
+import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
+import androidx.core.telecom.internal.utils.Utils
+import androidx.core.telecom.test.utils.BaseTelecomTest
+import androidx.core.telecom.test.utils.ManagedConnection
+import androidx.core.telecom.test.utils.ManagedConnectionService
+import androidx.core.telecom.test.utils.TestUtils
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SdkSuppress
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * NOTE: This class requires a minSdkVersion = Build.VERSION_CODES.Q
+ *
+ * [ManagedCallsTest] should be used to test core-telecom with traditional sim calling.
+ */
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+@RequiresApi(Build.VERSION_CODES.Q)
+@RunWith(AndroidJUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class ManagedCallsTest : BaseTelecomTest() {
+    private val address = Uri.parse("tel:555-TEST")
+    private val mManagedConnectionService = ManagedConnectionService()
+    private val mPhoneAccountHandle = PhoneAccountHandle(
+        ComponentName(
+            "androidx.core.telecom.test",
+            "androidx.core.telecom.test.utils.ManagedConnectionService"
+        ), "2"
+    )
+    private val mPhoneAccount = PhoneAccount.builder(mPhoneAccountHandle, "ManagedJetpackAcct")
+        .setAddress(address)
+        .setSubscriptionAddress(address)
+        .setCapabilities(
+            PhoneAccount.CAPABILITY_CALL_PROVIDER or
+                PhoneAccount.CAPABILITY_VIDEO_CALLING or
+                PhoneAccount.CAPABILITY_RTT or
+                PhoneAccount.CAPABILITY_CONNECTION_MANAGER or
+                PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS or
+                PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING
+        )
+        .addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
+        .addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
+        .build()
+
+    @Before
+    fun setUp() {
+        Utils.resetUtils()
+        mTelecomManager.registerPhoneAccount(mPhoneAccount)
+        TestUtils.enablePhoneAccountHandle(mContext, mPhoneAccountHandle)
+    }
+
+    @After
+    fun onDestroy() {
+        Utils.resetUtils()
+        mTelecomManager.unregisterPhoneAccount(mPhoneAccountHandle)
+    }
+
+    /**
+     * verify simulated managed calling is working in the jetpack layer.
+     */
+    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+    @LargeTest
+    @Test
+    fun testAddManagedCall() {
+        val deferredConnection = CompletableDeferred<ManagedConnection>()
+        runBlocking {
+            val connection = addManagedCall(TestUtils.OUTGOING_CALL_ATTRIBUTES, deferredConnection)
+            disconnectAndDestroyConnection(connection)
+        }
+    }
+
+    /***********************************************************************************************
+     *                           Helpers
+     *********************************************************************************************/
+
+    private suspend fun addManagedCall(
+        callAttributes: CallAttributesCompat,
+        deferredConnection: CompletableDeferred<ManagedConnection>
+    ): ManagedConnection {
+        val request = ManagedConnectionService.PendingConnectionRequest(
+            callAttributes, deferredConnection
+        )
+        mManagedConnectionService.createConnectionRequest(
+            mTelecomManager,
+            mPhoneAccountHandle,
+            request
+        )
+        deferredConnection.await()
+        val connection = deferredConnection.getCompleted()
+        delay(10)
+        connection.setActive()
+        delay(10)
+        return connection
+    }
+
+    private fun disconnectAndDestroyConnection(connection: ManagedConnection) {
+        connection.setDisconnected(DisconnectCause(DisconnectCause.LOCAL))
+        connection.destroy()
+    }
+}
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/BaseTelecomTest.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/BaseTelecomTest.kt
similarity index 99%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/BaseTelecomTest.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/BaseTelecomTest.kt
index 7c7dcd3..e758e7b 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/BaseTelecomTest.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/BaseTelecomTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom.utils
+package androidx.core.telecom.test.utils
 
 import android.content.Context
 import android.content.pm.PackageManager
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnection.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnection.kt
new file mode 100644
index 0000000..3855142
--- /dev/null
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnection.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.test.utils
+
+import android.os.Build
+import androidx.annotation.RequiresApi
+
+/**
+ * [ManagedConnection] is an extension of the [android.telecom.Connection] class.
+ */
+@RequiresApi(Build.VERSION_CODES.O)
+class ManagedConnection : android.telecom.Connection()
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnectionService.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnectionService.kt
new file mode 100644
index 0000000..1d7e7d0
--- /dev/null
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/ManagedConnectionService.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.core.telecom.test.utils
+
+import android.os.Build
+import android.telecom.Connection
+import android.telecom.ConnectionRequest
+import android.telecom.ConnectionService
+import android.telecom.PhoneAccountHandle
+import android.telecom.TelecomManager
+import android.telecom.VideoProfile
+import androidx.annotation.RequiresApi
+import androidx.core.telecom.CallAttributesCompat
+import androidx.core.telecom.internal.utils.Utils
+import androidx.test.platform.app.InstrumentationRegistry
+import kotlinx.coroutines.CompletableDeferred
+
+/**
+ * NOTE: This class requires a DUT that has Build.VERSION_CODES.Q or higher in oder to create
+ * connections. This is due to the user of [androidx.test.platform.app.InstrumentationRegistry]
+ * dependency.
+ *
+ * [ManagedConnectionService] is a ConnectionService that simulates managed/sim calls. Managed calls
+ * have to be simulated because the devices being used for testing are not guaranteed to have sims.
+ */
+@RequiresApi(Build.VERSION_CODES.Q)
+class ManagedConnectionService : ConnectionService() {
+    data class PendingConnectionRequest(
+        val callAttributes: CallAttributesCompat,
+        val completableDeferred: CompletableDeferred<ManagedConnection>?
+    )
+
+    companion object {
+        var mPendingConnectionRequests: ArrayList<PendingConnectionRequest> = ArrayList()
+    }
+
+    fun createConnectionRequest(
+        telecomManager: TelecomManager,
+        phoneAccountHandle: PhoneAccountHandle,
+        pendingConnectionRequest: PendingConnectionRequest,
+    ) {
+        pendingConnectionRequest.callAttributes.mHandle = phoneAccountHandle
+
+        // add request to list
+        mPendingConnectionRequests.add(pendingConnectionRequest)
+
+        val extras = Utils.getBundleWithPhoneAccountHandle(
+            pendingConnectionRequest.callAttributes,
+            pendingConnectionRequest.callAttributes.mHandle!!
+        )
+
+        val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
+        uiAutomation.adoptShellPermissionIdentity("android.permission.CALL_PHONE")
+
+        // Call into the platform to start call
+        if (pendingConnectionRequest.callAttributes.isOutgoingCall()) {
+            telecomManager.placeCall(
+                pendingConnectionRequest.callAttributes.address, extras
+            )
+        } else {
+            telecomManager.addNewIncomingCall(
+                pendingConnectionRequest.callAttributes.mHandle, extras
+            )
+        }
+        uiAutomation.dropShellPermissionIdentity()
+    }
+
+    /**
+     *  Outgoing Connections
+     */
+    override fun onCreateOutgoingConnection(
+        connectionManagerAccount: PhoneAccountHandle,
+        request: ConnectionRequest
+    ): Connection? {
+        return createSelfManagedConnection(
+            request, CallAttributesCompat.DIRECTION_OUTGOING
+        )
+    }
+
+    override fun onCreateOutgoingConnectionFailed(
+        connectionManagerPhoneAccount: PhoneAccountHandle,
+        request: ConnectionRequest
+    ) {
+        val pendingRequest: PendingConnectionRequest? = findTargetPendingConnectionRequest(
+            request, CallAttributesCompat.DIRECTION_OUTGOING
+        )
+        pendingRequest?.completableDeferred?.cancel()
+
+        mPendingConnectionRequests.remove(pendingRequest)
+    }
+
+    /**
+     *  Incoming Connections
+     */
+    override fun onCreateIncomingConnection(
+        connectionManagerPhoneAccount: PhoneAccountHandle,
+        request: ConnectionRequest
+    ): Connection? {
+        return createSelfManagedConnection(
+            request, CallAttributesCompat.DIRECTION_INCOMING
+        )
+    }
+
+    override fun onCreateIncomingConnectionFailed(
+        connectionManagerPhoneAccount: PhoneAccountHandle,
+        request: ConnectionRequest
+    ) {
+        val pendingRequest: PendingConnectionRequest? = findTargetPendingConnectionRequest(
+            request, CallAttributesCompat.DIRECTION_INCOMING
+        )
+        pendingRequest?.completableDeferred?.cancel()
+        mPendingConnectionRequests.remove(pendingRequest)
+    }
+
+    internal fun createSelfManagedConnection(
+        request: ConnectionRequest,
+        direction: Int
+    ): Connection? {
+        val targetRequest: PendingConnectionRequest =
+            findTargetPendingConnectionRequest(request, direction) ?: return null
+
+        val jetpackConnection = ManagedConnection()
+
+        // set display name
+        jetpackConnection.setCallerDisplayName(
+            targetRequest.callAttributes.displayName.toString(), TelecomManager.PRESENTATION_ALLOWED
+        )
+
+        // set address
+        jetpackConnection.setAddress(
+            targetRequest.callAttributes.address, TelecomManager.PRESENTATION_ALLOWED
+        )
+
+        // set the call state for the given direction
+        if (direction == CallAttributesCompat.DIRECTION_OUTGOING) {
+            jetpackConnection.setDialing()
+        } else {
+            jetpackConnection.setRinging()
+        }
+
+        // set the callType
+        if (targetRequest.callAttributes.callType == CallAttributesCompat.CALL_TYPE_VIDEO_CALL) {
+            jetpackConnection.videoState = VideoProfile.STATE_BIDIRECTIONAL
+        } else {
+            jetpackConnection.videoState = VideoProfile.STATE_AUDIO_ONLY
+        }
+
+        // set the call capabilities
+        if (targetRequest.callAttributes.hasSupportsSetInactiveCapability()) {
+            jetpackConnection.connectionCapabilities =
+                Connection.CAPABILITY_HOLD or Connection.CAPABILITY_SUPPORT_HOLD
+        }
+
+        targetRequest.completableDeferred?.complete(jetpackConnection)
+        mPendingConnectionRequests.remove(targetRequest)
+
+        return jetpackConnection
+    }
+
+    /**
+     *  Helper methods
+     */
+    private fun findTargetPendingConnectionRequest(
+        request: ConnectionRequest,
+        direction: Int
+    ): PendingConnectionRequest? {
+        for (pendingConnectionRequest in mPendingConnectionRequests) {
+            if (isSameAddress(pendingConnectionRequest.callAttributes, request) && isSameDirection(
+                    pendingConnectionRequest.callAttributes, direction
+                ) && isSameHandle(pendingConnectionRequest.callAttributes.mHandle, request)
+            ) {
+                return pendingConnectionRequest
+            }
+        }
+        return null
+    }
+
+    private fun isSameDirection(callAttributes: CallAttributesCompat, direction: Int): Boolean {
+        return (callAttributes.direction == direction)
+    }
+
+    private fun isSameAddress(
+        callAttributes: CallAttributesCompat,
+        request: ConnectionRequest
+    ): Boolean {
+        return request.address?.equals(callAttributes.address) ?: false
+    }
+
+    private fun isSameHandle(handle: PhoneAccountHandle?, request: ConnectionRequest): Boolean {
+        return request.accountHandle?.equals(handle) ?: false
+    }
+}
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockDialerActivity.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockDialerActivity.kt
similarity index 95%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockDialerActivity.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockDialerActivity.kt
index 5488aa2..14a9e5e 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockDialerActivity.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockDialerActivity.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom.utils
+package androidx.core.telecom.test.utils
 
 import android.app.Activity
 import android.os.Bundle
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockInCallService.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockInCallService.kt
similarity index 98%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockInCallService.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockInCallService.kt
index ca22f94..95fcd26 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/MockInCallService.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/MockInCallService.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom.utils
+package androidx.core.telecom.test.utils
 
 import android.content.Intent
 import android.os.Build
diff --git a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/TestUtils.kt b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
similarity index 90%
rename from core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/TestUtils.kt
rename to core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
index bac414f..d38fd18 100644
--- a/core/core-telecom/src/androidTest/java/androidx/core/telecom/utils/TestUtils.kt
+++ b/core/core-telecom/src/androidTest/java/androidx/core/telecom/test/utils/TestUtils.kt
@@ -14,10 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.core.telecom.utils
+package androidx.core.telecom.test.utils
 
+import android.content.Context
 import android.net.Uri
 import android.os.Build.VERSION_CODES
+import android.os.UserHandle
+import android.os.UserManager
 import android.telecom.Call
 import android.telecom.DisconnectCause
 import android.telecom.PhoneAccountHandle
@@ -44,6 +47,7 @@
     const val COMMAND_SET_DEFAULT_DIALER = "telecom set-default-dialer " // DO NOT REMOVE SPACE
     const val COMMAND_GET_DEFAULT_DIALER = "telecom get-default-dialer"
     const val COMMAND_CLEANUP_STUCK_CALLS = "cleanup-stuck-calls"
+    const val COMMAND_ENABLE_PHONE_ACCOUNT = "telecom set-phone-account-enabled "
     const val COMMAND_DUMP_TELECOM = "dumpsys telecom"
     const val TEST_CALL_ATTRIB_NAME = "Elon Musk"
     const val OUTGOING_NAME = "Larry Page"
@@ -221,6 +225,24 @@
         )
     }
 
+    fun enablePhoneAccountHandle(context: Context, phoneAccountHandle: PhoneAccountHandle) {
+        val pn = phoneAccountHandle.componentName.packageName
+        val cn = phoneAccountHandle.componentName.className
+        val userHandleId = getCurrentUserSerialNumber(context, phoneAccountHandle.userHandle)
+        Log.i(
+            LOG_TAG,
+            "enable phoneAccountHandle=[$phoneAccountHandle], success=[${
+                runShellCommand(
+                    (COMMAND_ENABLE_PHONE_ACCOUNT +
+                        pn + "/" + cn + " " + phoneAccountHandle.id + " " + userHandleId)
+                )
+            }]"
+        )
+    }
+    private fun getCurrentUserSerialNumber(context: Context, userHandle: UserHandle): Long {
+        val userManager = context.getSystemService(UserManager::class.java)
+        return userManager.getSerialNumberForUser(userHandle)
+    }
     fun getDefaultDialer(): String {
         val s = runShellCommand(COMMAND_GET_DEFAULT_DIALER)
         return s.replace("\n", "")