如何检测拨出电话响应

问题描述

我的任务是找到一种方法(如果有的话)来检测接听者何时接听了拨出电话。

经过一些研究,我尝试了以下方法

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 (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...