首页 > 解决方案 > 使用 TelecomManager.placeCall 进行自定义呼叫

问题描述

我正在尝试在两个已在其设备上安装我的应用程序的用户之间使用 TelecomManager 进行呼叫的自定义实现

按照本指南,我实现了连接服务、Connection 的子类、添加权限、注册了 PhoneAccount 等等......

我已经第三周努力理解的事情是如何在不使用电话号码但用户名或用户 ID 的情况下在我的应用程序用户之间拨打电话。

下面的代码开始从我的设备拨打电话,但此电话永远不会到达最终用户设备

telecomManager.placeCall(Uri.fromParts(/*tried also with PhoneAccount.SCHEME_SIP and PhoneAccount.SCHEME_TEL*/
                        TripmateConnectionService.SCHEME_AG, "userId", null), extras)

需要提及的是,在我的 BroadcastReceiver 实现中,我可以检测到来自其他应用程序的传入呼叫,因此我似乎正确处理了呼叫检测,并且来自上述代码的呼叫从未真正发送到预期的用户设备。

现在是问题所在。我觉得我错过了一些重要的东西。具有相同应用程序的设备如何在没有电话号码的情况下相互通信?将用户名传递给 telemanager.placeCall 真的足够了吗,它应该设法找到安装了应用程序的正确设备并拨打电话?telemanager如何区分在哪里拨打电话?

对不起,不清楚的问题,这是我第一次做与电话有关的事情,我觉得我很幸运地理解了这个主题,而且很难让问题更具体,因为我不完全知道我错过了什么。

我将在下面放一些我现在正在使用的代码

开始拨出电话

 private fun placeSystemCall(myUid: String, peerUid: String, channel: String, role: Int) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val extras = Bundle()
            extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_BIDIRECTIONAL)
            val extraBundle = Bundle()
            extraBundle.putString(Constants.CS_KEY_UID, myUid)
            extraBundle.putString(Constants.CS_KEY_SUBSCRIBER, peerUid)
            extraBundle.putString(Constants.CS_KEY_CHANNEL, channel)
            extraBundle.putInt(Constants.CS_KEY_ROLE, Constants.CALL_ID_OUT)
            extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extraBundle)
            try {
                val telecomManager = applicationContext.getSystemService(TELECOM_SERVICE) as TelecomManager
                val pa: PhoneAccount = telecomManager.getPhoneAccount(
                        config().phoneAccountOut?.accountHandle)
                extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
                extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, pa.accountHandle)
                telecomManager.placeCall(Uri.fromParts(
                        TripmateConnectionService.SCHEME_AG, peerUid, null), extras)
            } catch (e: SecurityException) {
                e.printStackTrace()
            }
        }
    }

在连接服务中

override fun onCreateOutgoingConnection(phoneAccount: PhoneAccountHandle?, request: ConnectionRequest): Connection {
        Log.i(TAG, "onCreateOutgoingConnection: called. $phoneAccount $request")
        val extras = request.extras
        val uid = extras.getString(Constants.CS_KEY_UID) ?: "0"
        val channel = extras.getString(Constants.CS_KEY_CHANNEL) ?: "0"
        val subscriber = extras.getString(Constants.CS_KEY_SUBSCRIBER) ?: "0"
        val role = extras.getInt(Constants.CS_KEY_ROLE)
        val videoState = extras.getInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE)
        val connection = TripmateConnection(applicationContext, uid, channel, subscriber, role)
        connection.setVideoState(videoState)
        connection.setAddress(Uri.fromParts(SCHEME_AG, subscriber, null), TelecomManager.PRESENTATION_ALLOWED)
        connection.setCallerDisplayName(subscriber, TelecomManager.PRESENTATION_ALLOWED)
        connection.setRinging()
        TMApplication.getInstance().config().setConnection(connection)
        return connection
    }

创建电话帐户

private fun registerPhoneAccount(context: Context) {
        val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as? TelecomManager
                ?: throw RuntimeException("cannot obtain telecom system service")

        val accountHandleIn = PhoneAccountHandle(
                ComponentName(context, TripmateConnectionService::class.java), Constants.PA_LABEL_CALL_IN)
        val accountHandleOut = PhoneAccountHandle(
                ComponentName(context, TripmateConnectionService::class.java), Constants.PA_LABEL_CALL_OUT)
        try {
            var paBuilder: PhoneAccount.Builder = PhoneAccount.builder(accountHandleIn, Constants.PA_LABEL_CALL_IN)
                    .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            val phoneIn = paBuilder.build()
            paBuilder = PhoneAccount.builder(accountHandleOut, Constants.PA_LABEL_CALL_OUT)
                    .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)
            val extra = Bundle()
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                extra.putBoolean(PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, true)
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                paBuilder.setExtras(extra)
            }
            val phoneOut = paBuilder.build()
            telecomManager.registerPhoneAccount(phoneIn)
            telecomManager.registerPhoneAccount(phoneOut)
            if (telecomManager.getPhoneAccount(phoneIn.accountHandle) == null || telecomManager.getPhoneAccount(phoneOut.accountHandle) == null) {
                throw RuntimeException("cannot create account");
            }
            mCallSession = TripmateCallSession()
            mCallSession?.phoneAccountIn = phoneIn
            mCallSession?.phoneAccountOut = phoneOut
        } catch (e: SecurityException) {
            throw RuntimeException("cannot create account", e);
        }
    }

感谢您的时间!任何可以帮助我理解更多的建议和链接将不胜感激!

标签: androidvoiptelecom-manager

解决方案


推荐阅读