Android 手机来电 获取来电信息,接听/挂断电话

目录

1.需求描述

2.实现原理

第一个:手机来电状态

第二个:获取手机来电号码

第三个:接听和挂断电话


1.需求描述

监听用户手机来电,弹起App内自定义的来电展示,并且展示来电电话,用户可以接通和挂断。

2.实现原理

这儿我就总结下手机来电、获取手机号码和接听/挂断电话,弹起App的来电展示界面使用的windowmanager。

第一个:手机来电状态

权限

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />//接/挂电话需要这个权限

private lateinit var telephonyManager: TelephonyManager
private lateinit var mPhoneListener: PhoneStateListener


//在你的onCreate里
......
telephonyManager = getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
        //在注册监听的时候就会走一次回调,后面通话状态改变时也会走
        //如下面的代码,在启动服务时如果手机没有通话相关动作,就会直接走一次TelephonyManager.CALL_STATE_IDLE
        mPhoneListener = object : PhoneStateListener() {
            override fun onCallStateChanged(state: Int, phoneNumber: String?) {
                super.onCallStateChanged(state, phoneNumber)
                when (state) {
                    //挂断
                    TelephonyManager.CALL_STATE_IDLE -> {
                        //toast("挂断${phoneNumber}")
                        Log.i("TAG", "onCallStateChanged: 挂断${phoneNumber}")
                    }
                    //接听
                    TelephonyManager.CALL_STATE_OFFHOOK -> {
                        Log.i("TAG", "onCallStateChanged: 接听${phoneNumber}")
                    }
                    //响铃
                    TelephonyManager.CALL_STATE_RINGING -> {
                        Log.i("TAG", "onCallStateChanged: 响铃${phoneNumber}")
                      LogUtils.e("来电${getLatestIncomingCallNumber(contentResolver)}")
                      }
                }
            }
        }
        telephonyManager.listen(mPhoneListener, PhoneStateListener.LISTEN_CALL_STATE)
......

这样就可以实时监听手机来电

第二个:获取手机来电号码

权限:

     <uses-permission android:name="android.permission.READ_CALL_LOG" />
     <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
    @SuppressLint("Range")
    private fun getLatestIncomingCallNumber(contentResolver: ContentResolver?): String? {
        var phoneNumber: String? = null
        var cursor: Cursor? = null
        try {
            if (contentResolver != null) {
                cursor = contentResolver.query(
                    CallLog.Calls.CONTENT_URI, arrayOf(CallLog.Calls.NUMBER),
                    CallLog.Calls.TYPE + " = " + CallLog.Calls.INCOMING_TYPE,
                    null,
                    CallLog.Calls.DATE + " DESC"
                )
                if (cursor != null && cursor.moveToFirst()) {
                    phoneNumber = cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER))
                }
            }
        } finally {
            cursor?.close()
        }
        return phoneNumber
    }

说实话,现在手机系统的来电展示不错了,所以这种App需要足够做的花哨好用才行,但是这又涉及用户的敏感权限和应用市场的卡脖子。emmm,不知道他的前景是什么?

第三个:接听和挂断电话

之前看了许多博客,结果发现,很多都是1几年的文章,很多方法都已经被废弃了,或者不适配高版本的android系统,于是去查了查开发者和stack overflow,emmmm,目前这个方法可行

首先是接电话,使用telecomManager,之前是telephonyManager?已经没有acceptRingingCall这个方法了。

 private fun answerCall() {
        val telecomManager =
            this.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ANSWER_PHONE_CALLS
            ) == PackageManager.PERMISSION_GRANTED
        ) {
            telecomManager.acceptRingingCall()
            LogUtils.e("telecomManager.接电话() finish")
        }
    }

其次是挂掉电话:

挂掉电话要根据android版本来做个适配:

fun userClickToEndCall(context: Context): Boolean {
        var callSuccess = false
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                val telecomManager =
                    context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
             

                if (ActivityCompat.checkSelfPermission(
                        context, Manifest.permission.ANSWER_PHONE_CALLS
                    ) == PackageManager.PERMISSION_GRANTED
                ) {
                    telecomManager.endCall()
                    callSuccess = true
                    Log.d(TAG, "telecomManager.endCall() finish")
                } else {
                    ToastUtils.showShort("No Permission!")
                }
            } else {
               
                val tm = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                val c = Class.forName(tm.javaClass.name)
                val m: Method = c.getDeclaredMethod("getITelephony")
                m.isAccessible = true
                val telephonyService: ITelephony = m.invoke(tm) as ITelephony
                callSuccess = telephonyService.endCall()
                Log.d(TAG, " telephonyService.endCall finish")
            }
        } catch (e: Exception) {
            Log.d(TAG, "Exception   error: " + e.message)
            callSuccess = disconnectCall()
            e.printStackTrace()
        }
        return callSuccess
    }

    private fun disconnectCall(): Boolean {
        try {
            Log.d(TAG, "input keyevent " + KeyEvent.KEYCODE_ENDCALL)
            Runtime.getRuntime().exec(
                "input keyevent " + KeyEvent.KEYCODE_ENDCALL.toString()
            ) //KEYCODE_HEADSETHOOK
        } catch (exc: Exception) {
            Log.d(TAG, "exc.printStackTrace")
            exc.printStackTrace()
            return false
        }
        return true
    }

上面当Android版本大于9时,使用telecomManager.endCall()

小于Android9时,利用反射的原理来调用方法,因为Api接口不公开了,调用不了。

1.获取TelephonyManager
   2.获取TelephonyManager.class
     3.反射调用TelephonyManager的 getITelephony方法获取ITelephony
         4.挂断电话ITelephony.endCall

猜你喜欢

转载自blog.csdn.net/LoveFHM/article/details/131559767