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

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利用反射调用了不公开的方法了。

相关作品

STUNT BIKE EXTREME - 免费在线玩!
bet体育365官网正规

STUNT BIKE EXTREME - 免费在线玩!

📅 09-19 👁️ 4886
新浪软件
365bet如何提款

新浪软件

📅 07-10 👁️ 1868
gtx1070显卡怎么样 gtx1070显卡详细参数评测[多图]
bet体育365官网正规

gtx1070显卡怎么样 gtx1070显卡详细参数评测[多图]

📅 07-12 👁️ 195