Android自动接听&挂断电话(包含怎么应对4.1以上版本的权限检查)
2014-09-22 14:28
459 查看
转自:http://bbs.51cto.com/thread-1078059-1.html
一前言
这两天要研究类似白名单黑名单以及手势自动接听的一些功能,所以呢,自然而然的涉及到怎么自动接听/挂断电话的功能了。
对于自动接听这一块,android4.1版本及其以上的版本和之前的版本处理逻辑不太一样,因为google增加了权限检查...所以,按照以前的方法可能不能实现自动接听了.
二android低版本自动接听/挂断实现
1.copyandroid源代码的ITelephony.aidl文件到自己的项目
为什么要copy这个文件到自己的项目中呢?这是因为接听/挂断电话的方法在接口ITelephony.java里面,而这个接口时隐藏的,也就是sdk开发是看不到这个接口的。
比如:
正如上面所说,这个接口ITelephony.java是隐藏的(@hide),它的包名时com.android.internal.telephony,所以,我们在我们的项目里面新建同样的一个包,
然后把系统的ITelephony.aidl拷贝过来.
由于ITelephony.aidl关联了NeighboringCellInfo.aidl,所以也一并拷贝过来。
不过要注意的是,NeighboringCellInfo.aidl所在的的包名是android.telephony;所以,你要新建一个包android.telephony,然后把NeighboringCellInfo.aidl放到
包android.telephony里面。
NeighboringCellInfo.aidl的定义:
b.使用ITelephony.java接口
上面一步完成之后,你就会在你的gen目录下发现已经生成了ITelephony.java这个接口文件。这样,我们就可以使用它了..
这里的话,主要是利用反射机制来取得ITelephony对象,为什么要用反射呢?因为ITelephony对象是以一个系统服务的形式存在系统中的,跟ams,wms等等一样。
一般通过ServiceManager来保存和获取。但是ServiceManager同样也是隐藏的,如:
所以,我们首先要通过反射的机制拿到ServiceManager对象,然后调用ServiceManager.getService(Stringname)方法来取得ITelephony对象。这个name就是当时
addService()的时候使用的name...
ok...那我们来看看反射出ServiceManager的代码怎么写。
解释下上面的代码,Class.forName(Strings)里面写的时ServiceManager类所在的完整包名和类型,这样就可以得到ServiceManager的Class对象。然后调用getMethod
方法,参数是getService,后面的String表示getService()方法的参数类型,也就是拿到了ServieManager的getService(Strings)这个方法。
嗯...既然已经得到了getService(Stringname)方法,那么就调用它!把要传入的参数,也就是想得到的Service的名字传入,这里我们传入"phone"字符串,就可以返回一个
IBinder对象。
那,为什么要传入"phone"这个名字呢?
这是因为ITelephony.java的实现类PhoneInterfaceManager.java在创建的时候,把自己添加进入了ServiceManager,然后使用的名字就是"phone"
如:
代码路径:
packages/apps/Phone/src/com/android/phone/PhoneInterfaceManager.java
代码:
嗯,大家看到没有,PhoneInterfaceManager实现了ITelephony接口,然后在publish的时候,调用了ServicerManager.addService(xxx),
把自己添加进入了ServiceManager,起的名字时"phone"。所以,我们只要调用getService("phone"),就可以拿到ITelephony的对象,也就是PhoneInterfaceManager对象。
c.调用ITelephony.java的answerRingingCall()方法接听电话
代码:
解释下上面两行代码:
第一行是把上面getService("phone")得到的IBinder对象binder转化成ITelephony对象,这是Binder机制的东西,就不讲了。大家只要记得Binder对象和具体对象和相互转换即可。
第二行是调用answerRingingCall()方法,这个方法调用之后,就会接通电话。
如果是挂断电话的话,就应该调用telephony.endCall()方法,这个相信大家也能理解的。
d.配置应用程序权限
最后,我们还需要在AndroidManifest.xml里面配置下权限:
如下:
上面自动接听电话的代码在4.1以前版本运行是没有问题的,但是新版本的android对接听电话函数(挂断电话没问题),也就是answerRingingCall(),增加权限检查。只有系统进程才有权限执行这个方法,
其他应用程序调用的话,就抛出一个异常:
复制内容到剪贴板
代码:
所以,对于高版本的手机的话,我们要用另外的方法来处理,这也是下面要讨论的问题。
三高版本自动接听电话
我们把整个代码贴出来,然后一行行解释
在上面的代码里面,最开始的代码和第二点讲解的时候,没有什么区别,主要看Exception发生之后,try{}里面的代码,也就是:
这里其实就是发送了一个广播就完事了,这个广播的action是"android.intent.action.MEDIA_BUTTON",然后还有一个参数---keyEvent
那么,这个广播有什么用呢?为什么可以自动接听电话呢?关于这一点,我们要看看这个广播的接受者怎么处理这个广播的。
代码路径:
packages/apps/Phone/src/com/android/phone/PhoneGlobals.java
代码:
/
解释下上面贴的代码
1.PhoneGlobals注册一个广播***,action就是上面我们发送的广播“android.intent.action.MEDIA_BUTTON”
ok..这个广播***接受到广播之后,就会执行onReceive()方法,也就是MediaButtonBroadcastReceiver的onReceive()方法。
在onReceive()方法里面,它会判断按下的keyEvent,如果是KeyEvent.KEYCODE_HEADSETHOOK的话,就会执行PhoneUtils.handleHeadsetHook(xxx)方法
在handleHeadsetHook(xxx)里面,会调用answerCall(phone.getRingingCall)方法,也就是接听电话了...
那么,就有个疑问,为什么android会提供这个MediaButtonBroadcastReceiver广播***呢?
其实,这个广播***是为了监听耳机上接听电话那个按钮的,耳机上有个按钮,来电时只要按一下,就可以接听电话,也就是会调用我们这个MediaButtonBroadcastReceiver
广播***。
那,这就给我们提供了方便之门,做自动接听程序的时候,尽管google已经增加了权限检查,但是我们通过绕过去的方式,利用MediaButtonBroadcastReceiver,从而达到了
我们的目的。
这算不算android的一个漏洞呢...
一前言
这两天要研究类似白名单黑名单以及手势自动接听的一些功能,所以呢,自然而然的涉及到怎么自动接听/挂断电话的功能了。
对于自动接听这一块,android4.1版本及其以上的版本和之前的版本处理逻辑不太一样,因为google增加了权限检查...所以,按照以前的方法可能不能实现自动接听了.
二android低版本自动接听/挂断实现
1.copyandroid源代码的ITelephony.aidl文件到自己的项目
为什么要copy这个文件到自己的项目中呢?这是因为接听/挂断电话的方法在接口ITelephony.java里面,而这个接口时隐藏的,也就是sdk开发是看不到这个接口的。
比如:
01 | package com.android.internal.telephony; |
02 | /** |
03 | * |
04 | * |
05 | * |
06 | * |
07 | *{@hide} |
08 | */ |
09 | public interface
extends android.os.IInterface |
10 | { |
11 | ... |
12 | } |
然后把系统的ITelephony.aidl拷贝过来.
由于ITelephony.aidl关联了NeighboringCellInfo.aidl,所以也一并拷贝过来。
不过要注意的是,NeighboringCellInfo.aidl所在的的包名是android.telephony;所以,你要新建一个包android.telephony,然后把NeighboringCellInfo.aidl放到
包android.telephony里面。
NeighboringCellInfo.aidl的定义:
1 | package android.telephony; |
2 |
3 | parcelable |
上面一步完成之后,你就会在你的gen目录下发现已经生成了ITelephony.java这个接口文件。这样,我们就可以使用它了..
这里的话,主要是利用反射机制来取得ITelephony对象,为什么要用反射呢?因为ITelephony对象是以一个系统服务的形式存在系统中的,跟ams,wms等等一样。
一般通过ServiceManager来保存和获取。但是ServiceManager同样也是隐藏的,如:
01 | /** |
02 | public final class
|
03 | ... |
04 | } |
05 |
06 | /** |
07 | * |
08 | * |
09 | * |
10 | * |
11 | */ |
12 | public static
|
13 | try { |
14 | IBinder |
15 | if
null ){ |
16 | return service; |
17 | } else { |
18 | return getIServiceManager().getService(name); |
19 | } |
20 | } catch
|
21 | Log.e(TAG, "error ,e); |
22 | } |
23 | return null ; |
24 | } |
addService()的时候使用的name...
ok...那我们来看看反射出ServiceManager的代码怎么写。
1 | Method "android.os.ServiceManager" ) |
2 | .getMethod( "getService" ,String. class ); |
3 | IBinder null , new Object[]{“phone”}); |
方法,参数是getService,后面的String表示getService()方法的参数类型,也就是拿到了ServieManager的getService(Strings)这个方法。
嗯...既然已经得到了getService(Stringname)方法,那么就调用它!把要传入的参数,也就是想得到的Service的名字传入,这里我们传入"phone"字符串,就可以返回一个
IBinder对象。
那,为什么要传入"phone"这个名字呢?
这是因为ITelephony.java的实现类PhoneInterfaceManager.java在创建的时候,把自己添加进入了ServiceManager,然后使用的名字就是"phone"
如:
代码路径:
packages/apps/Phone/src/com/android/phone/PhoneInterfaceManager.java
代码:
01 | /** |
02 | * |
03 | */ |
04 | public class
extends
|
05 | .... |
06 |
07 | private
|
08 | mApp |
09 | mPhone |
10 | mCM |
11 | mAppOps |
12 | mMainThreadHandler new MainThreadHandler(); |
13 | publish(); |
14 | } |
15 |
16 | private void
|
17 | ServiceManager.addService( "phone" , this ); |
18 | } |
19 | } |
把自己添加进入了ServiceManager,起的名字时"phone"。所以,我们只要调用getService("phone"),就可以拿到ITelephony的对象,也就是PhoneInterfaceManager对象。
c.调用ITelephony.java的answerRingingCall()方法接听电话
代码:
1 | ITelephony |
2 | telephony.answerRingingCall(); |
第一行是把上面getService("phone")得到的IBinder对象binder转化成ITelephony对象,这是Binder机制的东西,就不讲了。大家只要记得Binder对象和具体对象和相互转换即可。
第二行是调用answerRingingCall()方法,这个方法调用之后,就会接通电话。
如果是挂断电话的话,就应该调用telephony.endCall()方法,这个相信大家也能理解的。
d.配置应用程序权限
最后,我们还需要在AndroidManifest.xml里面配置下权限:
如下:
1 | < uses-permission android:name = "android.permission.CALL_PHONE" /> |
2 | < uses-permission android:name = "android.permission.MODIFY_PHONE_STATE" /> |
其他应用程序调用的话,就抛出一个异常:
复制内容到剪贴板
代码:
D/Sandy(9058):java.lang.SecurityException:Neitheruser10125norcurrentprocesshasandroid.permission.MODIFY_PHONE_STATE.
D/Sandy(9058):atandroid.os.Parcel.readException(Parcel.java:1327)
D/Sandy(9058):atandroid.os.Parcel.readException(Parcel.java:1281)
D/Sandy(9058):atcom.android.internal.telephony.ITelephony$Stub$Proxy.answerRingingCall(ITelephony.java:1019)
D/Sandy(9058):atcom.example.hillrestproject.service.PhonePickupService.onPickUpEvent(PhonePickupService.java:180)
D/Sandy(9058):atcom.hcrest.gestures.pickup.PickUpDetector.onSensorData(PickUpDetector.java:150)
D/Sandy(9058):atcom.hcrest.android.sensors.SensorManagerAdapter$ListenerDelegate.onSensorChanged(SensorManagerAdapter.java:373)
D/Sandy(9058):atandroid.hardware.SensorManager$ListenerDelegate$1.handleMessage(SensorManager.java:635)
D/Sandy(9058):atandroid.os.Handler.dispatchMessage(Handler.java:99)
D/Sandy(9058):atandroid.os.Looper.loop(Looper.java:137)
D/Sandy(9058):atandroid.app.ActivityThread.main(ActivityThread.java:4507)
D/Sandy(9058):atjava.lang.reflect.Method.invokeNative(NativeMethod)
D/Sandy(9058):atjava.lang.reflect.Method.invoke(Method.java:511)
D/Sandy(9058):atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:980)
D/Sandy(9058):atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:747)
D/Sandy(9058):atdalvik.system.NativeStart.main(NativeMethod)
所以,对于高版本的手机的话,我们要用另外的方法来处理,这也是下面要讨论的问题。
三高版本自动接听电话
我们把整个代码贴出来,然后一行行解释
01 | try { |
02 | Method "android.os.ServiceManager" ) |
03 | .getMethod( "getService" ,String. class ); |
04 |
05 | IBinder null , new Object[]{TELEPHONY_SERVICE}); |
06 |
07 | ITelephony |
08 |
09 | telephony.answerRingingCall(); |
10 |
11 | } catch
|
12 | Log.d( "Sandy" , "" ,e); |
13 | } catch
|
14 | Log.d( "Sandy" , "" ,e); |
15 | } catch
|
16 | Log.d( "Sandy" , "" ,e); |
17 | try { |
18 | Log.e( "Sandy" , "for ); |
19 | Intent new Intent( "android.intent.action.MEDIA_BUTTON" ); |
20 | KeyEvent new
|
21 | intent.putExtra( "android.intent.extra.KEY_EVENT" ,keyEvent); |
22 | sendOrderedBroadcast(intent, "android.permission.CALL_PRIVILEGED" ); |
23 | } catch
|
24 | Log.d( "Sandy" , "" ,e2); |
25 | Intent new Intent(Intent.ACTION_MEDIA_BUTTON); |
26 | KeyEvent new
|
27 | meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT,keyEvent); |
28 | sendOrderedBroadcast(meidaButtonIntent, null ); |
29 | } |
30 | } |
1 | Log.e( "Sandy" , "for ); |
2 | Intent new Intent( "android.intent.action.MEDIA_BUTTON" ); |
3 | KeyEvent new
|
4 | intent.putExtra( "android.intent.extra.KEY_EVENT" ,keyEvent); |
5 | sendOrderedBroadcast(intent, "android.permission.CALL_PRIVILEGED" ); |
那么,这个广播有什么用呢?为什么可以自动接听电话呢?关于这一点,我们要看看这个广播的接受者怎么处理这个广播的。
代码路径:
packages/apps/Phone/src/com/android/phone/PhoneGlobals.java
代码:
1 | IntentFilter new
|
2 | mediaButtonIntentFilter.setPriority( 1 ); |
3 | registerReceiver(mMediaButtonReceiver,mediaButtonIntentFilter); |
01 | / for
|
02 | private final
new MediaButtonBroadcastReceiver(); |
03 |
04 |
05 | protected class
extends
|
06 | <a " target= "_blank" > @Override </a> |
07 | public void
|
08 | KeyEvent |
09 |
10 | if
null ) |
11 | && |
12 |
13 | boolean
|
14 | ..... |
15 | } else { |
16 | .... |
17 | } |
18 | } |
19 | } |
1 | static boolean
|
2 | ... |
3 | answerCall(phone.getRingingCall()); |
4 | ... |
5 | } |
1.PhoneGlobals注册一个广播***,action就是上面我们发送的广播“android.intent.action.MEDIA_BUTTON”
ok..这个广播***接受到广播之后,就会执行onReceive()方法,也就是MediaButtonBroadcastReceiver的onReceive()方法。
在onReceive()方法里面,它会判断按下的keyEvent,如果是KeyEvent.KEYCODE_HEADSETHOOK的话,就会执行PhoneUtils.handleHeadsetHook(xxx)方法
在handleHeadsetHook(xxx)里面,会调用answerCall(phone.getRingingCall)方法,也就是接听电话了...
那么,就有个疑问,为什么android会提供这个MediaButtonBroadcastReceiver广播***呢?
其实,这个广播***是为了监听耳机上接听电话那个按钮的,耳机上有个按钮,来电时只要按一下,就可以接听电话,也就是会调用我们这个MediaButtonBroadcastReceiver
广播***。
那,这就给我们提供了方便之门,做自动接听程序的时候,尽管google已经增加了权限检查,但是我们通过绕过去的方式,利用MediaButtonBroadcastReceiver,从而达到了
我们的目的。
这算不算android的一个漏洞呢...
相关文章推荐
- Android自动接听&挂断电话(包含怎么应对4.1以上版本的权限检
- Android自动接听&挂断电话(包含怎么应对4.1以上版本的权限检)
- Android自动接听和挂断电话实现原理
- Android自动接听和挂断电话实现原理
- android 4.0以上系统如何实现自动接听电话
- ANDROID 自动接听 支持2.3以上版本
- [应用代码] android 自动接听电话和挂断 (适合目前所有版本)
- 4.1版本以后,利用耳机按键广播实现自动接听电话
- 使用ant让Android自动打包的build.xml,自动生成签名的apk文件(支持android4.0以上的版本) .
- 使用ant让Android自动打包的build.xml,自动生成签名的apk文件(支持android4.0以上的版本)
- Android 电话的反射调用机制实现自动接听电话
- Android中高版本拦截到骚扰电话自动挂断的实现
- android 来电自动接听和自动挂断(2.3以上)
- android 2.1 监听电话状态并自动接听来电
- Android(AIDL)自动重复拨号及挂断/接听电话
- Android&nbsp;4.1以上实现归属地JA…
- Android 自动接听电话和挂断
- android自动接听和挂断电话
- android 2.1 监听电话状态并自动接听来电
- 自动接听挂断电话