android - 来电时,InCallService 的 onCallAdded(Call call) 方法在主线程仍在运行时不会被调用
问题描述
我正在寻找什么解决方案
每次在主线程中调用时,如何调用 InCallService 的 onCallAdded(Call call) 方法(使用#repeat 进行循环)。
背景
我正在编写一个小型 Android 自动测试应用程序来自动拨打电话,然后进行网页浏览……等 10 个周期。
我的代码基于这篇文章:使用 android.telecom 和 InCallService 接听来电
它是如何工作的
- 这是 MainActivity:当我单击按钮(autoCall)时,开始重复调用 $autoCallNumber。
import android.Manifest
import android.content.Intent
import android.os.Bundle
import android.os.CountDownTimer
import android.telecom.TelecomManager
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.PermissionChecker
import androidx.core.net.toUri
import kotlinx.android.synthetic.main.activity_call.*
import kotlinx.android.synthetic.main.activity_dialer.*
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.TimeUnit
class MainActivity : AppCompatActivity() {
private val TAG = "${javaClass.simpleName} Wynne"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
offerReplacingDefaultDialer()
autoCall.setOnClickListener {
repeat(2) { i ->
makeCall()
Log.d(TAG,"We are on the ${i + 1}. loop")
TimeUnit.SECONDS.sleep(5);
}
}
}
private fun makeCall() {
if (PermissionChecker.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PermissionChecker.PERMISSION_GRANTED) {
var User: GeneralSettings = applicationContext as GeneralSettings
User.ongoingCalltype = "MO"
val uri = "tel:${User.autoCallNumber}".toUri()
startActivity(Intent(Intent.ACTION_CALL, uri))
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CALL_PHONE),
DialerActivity.REQUEST_PERMISSION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == DialerActivity.REQUEST_PERMISSION && PermissionChecker.PERMISSION_GRANTED in grantResults) {
makeCall()
}
}
private fun offerReplacingDefaultDialer() {
if (getSystemService(TelecomManager::class.java).defaultDialerPackage != packageName) {
Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER)
.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName)
.let(::startActivity)
}
}
}
- 这是对象:Ongoingcall(让我处理接听或挂断)
package com.github.arekolek.phone
import android.telecom.Call
import android.telecom.VideoProfile
import android.util.Log
import io.reactivex.subjects.BehaviorSubject
import timber.log.Timber
object OngoingCall {
val state: BehaviorSubject<Int> = BehaviorSubject.create()
private val TAG = "${javaClass.simpleName} Wynne"
private val callback = object : Call.Callback() {
override fun onStateChanged(call: Call, newState: Int) {
Log.d(TAG,"${call.toString()}")
state.onNext(newState)
Log.d(TAG,"New state : $newState")
}
}
var call: Call? = null
set(value) {
field?.unregisterCallback(callback)
value?.let {
it.registerCallback(callback)
state.onNext(it.state)
}
field = value
}
fun answer() {
call!!.answer(VideoProfile.STATE_AUDIO_ONLY)
}
fun hangup() {
call!!.disconnect()
}
}
- 这是 CallService(重写 InCallService 的 onCallAdded/onCallRemoved 以在呼叫到达/移除时处理活动)
package com.github.arekolek.phone
import android.telecom.Call
import android.telecom.InCallService
import android.util.Log
class CallService : InCallService() {
private val TAG = "${javaClass.simpleName} Wynne"
override fun onCallAdded(call: Call) {
OngoingCall.call = call
try {
CallActivity.start(this, call)
Log.d(TAG,"Start Call Activity")
}
catch ( e : Exception ) {
Log.d(TAG,"$e")
}
}
override fun onCallRemoved(call: Call) {
OngoingCall.call = null
}
}
- 这是呼叫活动(更新 UI 上的呼叫信息和挂断未知呼叫...等)
package com.github.arekolek.phone
import android.R.id.button1
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.telecom.Call
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.android.synthetic.main.activity_call.*
import java.util.concurrent.TimeUnit
class CallActivity : AppCompatActivity() {
private val TAG = javaClass.simpleName
private val disposables = CompositeDisposable()
private lateinit var ongoingCallNumber: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_call)
ongoingCallNumber = intent.data.schemeSpecificPart
}
override fun onStart() {
super.onStart()
var User: GeneralSettings = applicationContext as GeneralSettings
OngoingCall.state
.subscribe(::updateUi)
.addTo(disposables)
OngoingCall.state
.filter { it == Call.STATE_DISCONNECTED }
.delay(1, TimeUnit.SECONDS)
.firstElement()
.subscribe { finish() }
.addTo(disposables)
if (User.ongoingCalltype == "MO") {
Handler().postDelayed(Runnable { hangup.performClick() }, 5000)
Log.d(TAG, "Wynne : End MO call after 5 second")
User.ongoingCalltype = ""
} else if (ongoingCallNumber == User.autoAnswerNumber) {
Handler().post(Runnable { answer.performClick() })
Log.d(TAG, "Wynne : Answer incoming call ${User.autoAnswerNumber} ")
}
else{
Handler().post(Runnable { hangup.performClick() })
Log.d(TAG, "Wynne : End Unknown incoming call $ongoingCallNumber ")
}
}
@SuppressLint("SetTextI18n")
private fun updateUi(state: Int) {
callInfo.text = "${state.asString().toLowerCase().capitalize()}\n$ongoingCallNumber"
answer.isVisible = state == Call.STATE_RINGING
hangup.isVisible = state in listOf(
Call.STATE_DIALING,
Call.STATE_RINGING,
Call.STATE_ACTIVE
)
}
override fun onStop() {
super.onStop()
disposables.clear()
}
companion object {
fun start(context: Context, call: Call) {
Intent(context, CallActivity::class.java)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setData(call.details.handle)
.let(context::startActivity)
}
}
}
- 这是AndroidManifest(绑定.CallService(重写InCallService))
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.arekolek.phone"
>
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:name=".GeneralSettings"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateAlwaysVisible|adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<!-- Handle links from other applications -->
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.DIAL" />
<!-- Populate the system chooser -->
<category android:name="android.intent.category.DEFAULT" />
<!-- Handle links in browsers -->
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tel" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".CallService"
android:permission="android.permission.BIND_INCALL_SERVICE">
<meta-data
android:name="android.telecom.IN_CALL_SERVICE_UI"
android:value="true"
/>
<intent-filter>
<action android:name="android.telecom.InCallService" />
</intent-filter>
</service>
<activity
android:name=".CallActivity">
</activity>
</application>
</manifest>
- 这是GeneralSettings(全局变量)
package com.github.arekolek.phone
import android.app.Application
class GeneralSettings : Application() {
val autoCallNumber: String = "0988102544"
var ongoingCalltype: String = ""
val autoAnswerNumber: String = "0905112980"
}
那有什么问题
CallService 的 onCallAdded() 应该在 #repeat 中的每个循环之后调用 makeCall()。
但是,根据调试消息,我假设在 autoCall.setOnClickListener 完成之前不会调用 CallService 的 onCallAdded() 。
这是调试消息
16:52:24.859 D/MainActivity Wynne: We are on the 1. loop
16:52:29.895 D/MainActivity Wynne: We are on the 2. loop
16:52:35.041 D/CallService Wynne: Start Call Activity
16:52:35.048 D/CallService Wynne: Start Call Activity
16:52:35.116 D/CallActivity: Wynne : End MO call after 5 second
16:52:40.161 D/OngoingCall Wynne: New state : 10
16:52:40.419 D/OngoingCall Wynne: New state : 7
16:52:41.551 D/CallActivity: Wynne : End Unknown incoming call 0988102544
有人可以告诉我:
每次在主线程中运行 makeCall() 时,如何调用 CallService 的 onCallAdded()?这样我就可以在下一个周期之前断开呼叫。
感谢您花时间阅读我的问题。
解决方案
推荐阅读
- android - 1.12更新后如何更换AndroidTouch+Keyprocessor(FlutterView弃用)
- javascript - 正确使用 React hooks + WebSockets
- listview - 对于绑定的列表视图,如何为 selectefd 行绑定行图标
- javascript - 如何在反应js中的array.map上的事件onclick上添加功能
- string - 通过'sed'在比赛之前/之后添加一个字符串
- c# - 打印 MVC 视图时避免截断单词
- azure - Azure AD B2C 策略使用
- node.js - Docker“检测到未定义的 Node.js 版本”
- javascript - 为什么我的 kafkajs 客户端(Node.js/express.js)在获取主题元数据时抛出“TypeError:topics.forEach 不是函数”?
- ios - 无法在 IOS 应用程序中导入“AWSMobileAnalytics”