Android 手机来电 获取来电信息,接听/挂断电话 |
您所在的位置:网站首页 › mate40pro接电话自动挂断 › Android 手机来电 获取来电信息,接听/挂断电话 |
目录 1.需求描述 2.实现原理 第一个:手机来电状态 第二个:获取手机来电号码 第三个:接听和挂断电话 1.需求描述监听用户手机来电,弹起App内自定义的来电展示,并且展示来电电话,用户可以接通和挂断。 2.实现原理这儿我就总结下手机来电、获取手机号码和接听/挂断电话,弹起App的来电展示界面使用的windowmanager。 第一个:手机来电状态权限 //接/挂电话需要这个权限 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) ......这样就可以实时监听手机来电 第二个:获取手机来电号码权限: @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 评论里说不能实现,我发现原来是我的aidl代码没有贴出来: 创建一个aidl文件: interface ITelephony { boolean endCall(); void answerRingingCall(); void silenceRinger(); }这样在运行后会生成这个文件,就相当于使用AIDL利用反射调用了不公开的方法了。 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |