问题描述
我的任务是找到一种方法(如果有的话)来检测接听者何时接听了拨出电话。
经过一些研究,我尝试了以下方法:
A. PHONE_STATE 操作的广播接收器
<receiver android:name=".Interceptor">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
但拨出电话永远不会在接听电话时通知。
class Interceptor: broadcastReceiver() {
override fun onReceive(context: Context,intent: Intent) {
try {
when (intent.getStringExtra(TelephonyManager.EXTRA_STATE)) {
TelephonyManager.EXTRA_STATE_RINGING -> {
showToast(context,"ringing")
}
TelephonyManager.EXTRA_STATE_IDLE -> {
showToast(context,"idle")
}
TelephonyManager.EXTRA_STATE_OFFHOOK -> {
showToast(context,"off hook")
}
else -> {
showToast(context,intent.getStringExtra(TelephonyManager.EXTRA_STATE)!!)
}
}
} catch (e: Exception) {
e.printstacktrace()
}
}
private fun showToast(context: Context,s: String) {
Toast.makeText(context,s,Toast.LENGTH_SHORT).show()
}
}
我知道 READ_PRECISE_PHONE_STATE,但此类权限仅适用于拨号程序、运营商应用程序或即时消息应用程序等应用程序。
B. TelecomManager + ConnectionService
@RequiresApi(Build.VERSION_CODES.M)
fun call(view: View) {
val telecomManager: TelecomManager = getSystemService(TELECOM_SERVICE) as TelecomManager
when {
ContextCompat.checkSelfPermission(this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED -> {
ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.CALL_PHONE),2333)
}
ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED -> {
ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.READ_PHONE_STATE),2334)
}
else -> {
try {
val phoneAccountHandle = PhoneAccountHandle(ComponentName(applicationContext,MyConnectionService::class.java),"dld")
val build = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
PhoneAccount
.builder(phoneAccountHandle,"1234") // phone account named 1234
.setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER or PhoneAccount.CAPABILITY_CALL_PROVIDER)
.build()
} else {
Todo("VERSION.SDK_INT < O")
}
telecomManager.registerPhoneAccount(build)
val parse = Uri.fromParts(PhoneAccount.SCHEME_TEL,PHONENUMBERTOCALL,null) // PHONENUMBERTOCALL == "1112223334",a valid telephone number
val extras = Bundle()
extras.putParcelable(EXTRA_PHONE_ACCOUNT_HANDLE,phoneAccountHandle)
telecomManager.placeCall(parse,extras)
} catch (e: SecurityException) {
e.printstacktrace()
}
}
}
}
@RequiresApi(Build.VERSION_CODES.M)
class MyConnectionService : ConnectionService() {
private val TAG = this@MyConnectionService::javaClass.name
override fun onCreate() {
super.onCreate()
Log.d(TAG,"onCreate: ")
}
override fun onStartCommand(intent: Intent,flags: Int,startId: Int): Int {
Log.d(TAG,"onStartCommand: ")
return super.onStartCommand(intent,flags,startId)
}
override fun onCreateIncomingConnection(connectionManagerPhoneAccount: PhoneAccountHandle,request: ConnectionRequest): Connection {
Log.d(TAG,"onCreateIncomingConnection: ")
return super.onCreateIncomingConnection(connectionManagerPhoneAccount,request)
}
override fun onCreateIncomingConnectionFailed(connectionManagerPhoneAccount: PhoneAccountHandle,request: ConnectionRequest) {
Log.d(TAG,"onCreateIncomingConnectionFailed: ")
super.onCreateIncomingConnectionFailed(connectionManagerPhoneAccount,request)
}
override fun onCreateOutgoingConnectionFailed(connectionManagerPhoneAccount: PhoneAccountHandle,"onCreateOutgoingConnectionFailed: ")
super.onCreateOutgoingConnectionFailed(connectionManagerPhoneAccount,request)
}
@RequiresApi(Build.VERSION_CODES.N_MR1)
override fun onCreateOutgoingConnection(connectionManagerPhoneAccount: PhoneAccountHandle,"onCreateOutgoingConnection: ")
val connection = MyConnection(false)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
connection.connectionProperties = Connection.PROPERTY_SELF_MANAGED
}
connection.setAddress(
request.address,TelecomManager.PRESENTATION_ALLOWED)
connection.extras = request.extras
connection.setinitialized()
return connection
}
override fun onCreateOutgoingHandoverConnection(fromPhoneAccountHandle: PhoneAccountHandle,"onCreateOutgoingHandoverConnection: ")
return super.onCreateOutgoingHandoverConnection(fromPhoneAccountHandle,request)
}
override fun onCreateIncomingHandoverConnection(fromPhoneAccountHandle: PhoneAccountHandle,"onCreateIncomingHandoverConnection: ")
return super.onCreateIncomingHandoverConnection(fromPhoneAccountHandle,request)
}
override fun onHandoverFailed(request: ConnectionRequest,error: Int) {
super.onHandoverFailed(request,error)
Log.d(TAG,"onHandoverFailed: ")
}
override fun onConference(connection1: Connection,connection2: Connection) {
super.onConference(connection1,connection2)
Log.d(TAG,"onConference: ")
}
override fun onRemoteConferenceAdded(conference: RemoteConference) {
super.onRemoteConferenceAdded(conference)
Log.d(TAG,"onRemoteConferenceAdded: ")
}
override fun onRemoteExistingConnectionAdded(connection: RemoteConnection) {
super.onRemoteExistingConnectionAdded(connection)
Log.d(TAG,"onRemoteExistingConnectionAdded: ")
}
override fun onConnectionServiceFocusLost() {
super.onConnectionServiceFocusLost()
Log.d(TAG,"onConnectionServiceFocusLost: ")
}
override fun onConnectionServiceFocusGained() {
super.onConnectionServiceFocusGained()
Log.d(TAG,"onConnectionServiceFocusGained: ")
}
}
@RequiresApi(Build.VERSION_CODES.M)
class MyConnection(isIncoming: Boolean): Connection() {
private val TAG = this@MyConnection::javaClass.name
init {
// Assume all calls are video capable.
// Assume all calls are video capable.
}
override fun onStateChanged(state: Int) {
super.onStateChanged(state)
Log.d(TAG,"onStateChanged: $state")
}
override fun onAnswer() {
super.onAnswer()
this.setActive()
Log.d(TAG,"onAnswer: ")
}
override fun ondisconnect() {
super.ondisconnect()
this.destroy()
Log.d(TAG,"ondisconnect: ")
}
}
但这些回调都没有触发
C. (替代解决方案)读取通话记录
private fun showCallLogs() {
if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,arrayOf(Manifest.permission.READ_CALL_LOG),PERMISSION_REQUEST_READ_LOGS)
} else {
val sb = StringBuffer()
val cursor = managedQuery(CallLog.Calls.CONTENT_URI,null,null)
// columns
val number = cursor.getColumnIndex(CallLog.Calls.NUMBER)
val duration = cursor.getColumnIndex(CallLog.Calls.DURATION)
val date = cursor.getColumnIndex(CallLog.Calls.DATE)
val type = cursor.getColumnIndex(CallLog.Calls.TYPE)
sb.append("Call Log : ")
while (cursor.movetoNext()) {
val phoneNumber = cursor.getString(number)
if (phoneNumber == PHONENUMBERTOCALL) {
// -- duration
val callDate = cursor.getString(date)
val callDayTime = Date(callDate.toLong())
// -- duration
if (callDayTime.month in 2..4) {
// -- duration
val callDuration = cursor.getString(duration)
// -- duration
// -- call type
val callType = cursor.getString(type)
val dirCode = callType.toInt()
var dir = ""
when (dirCode) {
CallLog.Calls.OUTGOING_TYPE -> dir = "OUTGOING"
CallLog.Calls.INCOMING_TYPE -> dir = "INCOMING"
CallLog.Calls.MISSED_TYPE -> dir = "MISSED"
}
// -- call type
sb.append("\n call report: \n date: $callDayTime \n call type: $dir \n duration: $callDuration")
sb.append("\n --------------------------------------------------")
}
}
}
cursor.close()
Log.d("INFO",sb.toString())
}
}
此解决方案有效,但在 PlayStore 中发布应用程序时会出现一些问题,因此这永远不会见光(不幸的是)。
感谢任何帮助,在此先感谢您。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)