Android 来电自动接听
来源:互联网 发布:ubuntu ftp上传文件 编辑:程序博客网 时间:2024/05/13 22:05
1、闲聊
今天闲来无事,刚好一个朋友需要做一个来电自动接听的功能,我一想,咦,这尼玛我还没做过,好吧,去看看!好吧,看就看吧那么我提来了,我该从哪儿入手呢?算了还是走老步奏把,我想去看了看Andorid api 文档找到了一个东西:
这个包 提供用于监视基本电话信息的api,如网络类型和连接状态,以及操作电话号码字符串的实用程序。
然后呢?我就在这里面找到了一个来电的监听器:
我以为到了这一步就好做了,然而我监听到了来电,却接听不了!What?怎么会这样?于是我就去逛一下博客,结果博客的来带你自动接听一团糟,思前想后,不是个办法啊,最总皇天不负有心人,我还是找到了一个关键的东西“aidl”!
2、AIDL
到了这里我们了解一下“aidl”是做啥的!AIDL是一个缩写,全称是Android Interface Definition Language,也就是Android接口定义语言。AIDL这门语言非常的简单,基本上它的语法和 Java 是一样的,只是在一些细微处有些许差别——毕竟它只是被创造出来简化Android程序员工作的。对于小白来说,AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service,这样你的APP可以和其他APP交互。当然它在我开发中最常用的还是写一些插件,如:Android ButterKnife Zelezny , Android Parcelable code generator , GsonFormat , Parcelable Code Generator(for kotlin)等。
多说无用,现在我们像一个小白一样的去使用它就行了,以后深入了解!
说到这儿,我就分享一个 Android系统aidl 的github地址:
https://github.com/android/platform_frameworks_base
3、找到被Android系统隐藏的方法
那么我就需要,建立一个aidl的文件夹,并且与java文件夹同级!如图:
来吧,我们直接上这几个文件的源码,上源码之前必须说的一点是,包名必须与android系统框架下的包名相同!
CellInfo.aidl
package android.telephony;parcelable CellInfo;
NeighboringCellInfo.aidl
package android.telephony;parcelable NeighboringCellInfo;
ITelephony.aidl
package com.android.internal.telephony;interface ITelephony { boolean endCall(); void answerRingingCall(); boolean enableDataConnectivity(); boolean disableDataConnectivity(); boolean isDataConnectivityPossible();}
到了这里我们编译一下就会发现:在编译文件中多了一个.class文件 : ( ITelephony ) ,如图位置:
ITelephony .class 源码如下:
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.android.internal.telephony;import android.os.Binder;import android.os.IBinder;import android.os.IInterface;import android.os.Parcel;import android.os.RemoteException;public interface ITelephony extends IInterface { boolean endCall() throws RemoteException; void answerRingingCall() throws RemoteException; boolean enableDataConnectivity() throws RemoteException; boolean disableDataConnectivity() throws RemoteException; boolean isDataConnectivityPossible() throws RemoteException; public abstract static class Stub extends Binder implements ITelephony { private static final String DESCRIPTOR = "com.android.internal.telephony.ITelephony"; static final int TRANSACTION_endCall = 1; static final int TRANSACTION_answerRingingCall = 2; static final int TRANSACTION_enableDataConnectivity = 3; static final int TRANSACTION_disableDataConnectivity = 4; static final int TRANSACTION_isDataConnectivityPossible = 5; public Stub() { this.attachInterface(this, "com.android.internal.telephony.ITelephony"); } public static ITelephony asInterface(IBinder obj) { if(obj == null) { return null; } else { IInterface iin = obj.queryLocalInterface("com.android.internal.telephony.ITelephony"); return (ITelephony)(iin != null && iin instanceof ITelephony?(ITelephony)iin:new ITelephony.Stub.Proxy(obj)); } } public IBinder asBinder() { return this; } public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { boolean _result; switch(code) { case 1: data.enforceInterface("com.android.internal.telephony.ITelephony"); _result = this.endCall(); reply.writeNoException(); reply.writeInt(_result?1:0); return true; case 2: data.enforceInterface("com.android.internal.telephony.ITelephony"); this.answerRingingCall(); reply.writeNoException(); return true; case 3: data.enforceInterface("com.android.internal.telephony.ITelephony"); _result = this.enableDataConnectivity(); reply.writeNoException(); reply.writeInt(_result?1:0); return true; case 4: data.enforceInterface("com.android.internal.telephony.ITelephony"); _result = this.disableDataConnectivity(); reply.writeNoException(); reply.writeInt(_result?1:0); return true; case 5: data.enforceInterface("com.android.internal.telephony.ITelephony"); _result = this.isDataConnectivityPossible(); reply.writeNoException(); reply.writeInt(_result?1:0); return true; case 1598968902: reply.writeString("com.android.internal.telephony.ITelephony"); return true; default: return super.onTransact(code, data, reply, flags); } } private static class Proxy implements ITelephony { private IBinder mRemote; Proxy(IBinder remote) { this.mRemote = remote; } public IBinder asBinder() { return this.mRemote; } public String getInterfaceDescriptor() { return "com.android.internal.telephony.ITelephony"; } public boolean endCall() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken("com.android.internal.telephony.ITelephony"); this.mRemote.transact(1, _data, _reply, 0); _reply.readException(); _result = 0 != _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public void answerRingingCall() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); try { _data.writeInterfaceToken("com.android.internal.telephony.ITelephony"); this.mRemote.transact(2, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public boolean enableDataConnectivity() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken("com.android.internal.telephony.ITelephony"); this.mRemote.transact(3, _data, _reply, 0); _reply.readException(); _result = 0 != _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public boolean disableDataConnectivity() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken("com.android.internal.telephony.ITelephony"); this.mRemote.transact(4, _data, _reply, 0); _reply.readException(); _result = 0 != _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public boolean isDataConnectivityPossible() throws RemoteException { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); boolean _result; try { _data.writeInterfaceToken("com.android.internal.telephony.ITelephony"); this.mRemote.transact(5, _data, _reply, 0); _reply.readException(); _result = 0 != _reply.readInt(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } }}
4、开始使用
这里我就不过来多介绍了!我们通过反射使用这个class文件,不过再次之前,需要先注册权限:
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /><uses-permission android:name="android.permission.CALL_PHONE" /><uses-permission android:name="android.permission.CALL_PRIVILEGED" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.READ_PHONE_STATE" /><uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /><uses-permission android:name="android.permission.WRITE_CONTACTS" /><uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
注册来电监听的源码:
TelephonyManager telephony = (TelephonyManager) getApplication() .getSystemService(Context.TELEPHONY_SERVICE);telephony.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: Log.i(TAG, "onCallStateChanged: 来电:" + incomingNumber); if (true) { answerPhone(); } else { endPhone(); } break; case TelephonyManager.CALL_STATE_IDLE: Log.i(TAG, "onCallStateChanged: 挂断:" + incomingNumber); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.i(TAG, "onCallStateChanged: 通话:" + incomingNumber); break; } super.onCallStateChanged(state, incomingNumber); }}, PhoneStateListener.LISTEN_CALL_STATE);
自动挂断的代码:
private void endPhone() { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"phone"}); ITelephony telephony = ITelephony.Stub.asInterface(binder); telephony.endCall(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); }}
自动接听的代码:
private void answerPhone() { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"phone"}); ITelephony telephony = ITelephony.Stub.asInterface(binder); telephony.answerRingingCall(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); }}
到了这里我以为可以自动接听了:然而我开始测试了一下自动挂断,咦,可以咯,我兴冲冲的有去测试了一下,What?Fuck!无形报错,最为致命!
报了一个没有注册”android.permission.MODIFY_PHONE_STATE”这个权限的错误,如图:
5、解决问题
好吧,我又去博客咯!找到了一个最简单粗暴的方法:
private void answerPhone() { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"phone"}); ITelephony telephony = ITelephony.Stub.asInterface(binder); telephony.answerRingingCall(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e) { Log.e(TAG, "" + e, e); try { Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); } catch (IOException e2) { // Runtime.exec(String) had an I/O problem, try to fall back String enforcedPerm = "android.permission.CALL_PRIVILEGED"; Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); sendOrderedBroadcast(btnDown, enforcedPerm); sendOrderedBroadcast(btnUp, enforcedPerm); } }}
6、测试
本人亲测几个测试机,发现7.0一下的手机,都行自动接听,当然自动挂断好像没有限制所有手机都可以吧!
最后贴一下整个自动接听、挂断的源码吧:
public class IncomingListenerActivity extends AppCompatActivity { private static final String TAG = "IncomingListenerActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_incoming_listener); initListener(); } private void initListener() { TelephonyManager telephony = (TelephonyManager) getApplication() .getSystemService(Context.TELEPHONY_SERVICE); telephony.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String incomingNumber) { switch (state) { case TelephonyManager.CALL_STATE_RINGING: Log.i(TAG, "onCallStateChanged: 来电:" + incomingNumber); if (true) { answerPhone(); } else { endPhone(); } break; case TelephonyManager.CALL_STATE_IDLE: Log.i(TAG, "onCallStateChanged: 挂断:" + incomingNumber); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.i(TAG, "onCallStateChanged: 通话:" + incomingNumber); break; } super.onCallStateChanged(state, incomingNumber); } }, PhoneStateListener.LISTEN_CALL_STATE); } private void endPhone() { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"phone"}); ITelephony telephony = ITelephony.Stub.asInterface(binder); telephony.endCall(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } } private void answerPhone() { Method method = null; try { method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder binder = (IBinder) method.invoke(null, new Object[]{"phone"}); ITelephony telephony = ITelephony.Stub.asInterface(binder); telephony.answerRingingCall(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (RemoteException e) { e.printStackTrace(); } catch (Exception e) { Log.e(TAG, "" + e, e); try { Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK)); } catch (IOException e2) { // Runtime.exec(String) had an I/O problem, try to fall back String enforcedPerm = "android.permission.CALL_PRIVILEGED"; Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK)); Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra( Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK)); sendOrderedBroadcast(btnDown, enforcedPerm); sendOrderedBroadcast(btnUp, enforcedPerm); } } }}
7、源码地址
https://github.com/fountaintao/CustomControl/blob/master/app/src/main/java/com/taoyong/customcontrol/IncomingListenerActivity.java
- Android 自动接听来电
- Android 自动接听来电
- Android 自动接听来电
- Android 来电自动接听
- android 来电自动接听和自动挂断
- android 来电自动接听和自动挂断
- android 来电自动接听和自动挂断
- 实现android自动接听来电功能
- 来电自动接听源码
- 来电自动接听
- Android来电自动接听,自动录音,自动回拨功能
- android 来电自动接听和自动挂断(2.3以上)
- android 2.1 监听电话状态并自动接听来电
- android 2.1 监听电话状态并自动接听来电
- android 2.1 监听电话状态并自动接听来电
- android 2.1 监听电话状态并自动接听来电
- android 2.1 监听电话状态并自动接听来电
- Windows Mobile 来电自动接听
- 求解两个n位数相乘的最大回文数(Python实现,效率较高)
- Android应用在未启动的情况下无法收到指定广播的问题总结
- 用shell写一个作业管理系统
- java写了个日历,其中遇到坑爹小问题(JTable)
- 【nlp】湖北师范大学贴吧帖子标题词频统计
- Android 来电自动接听
- 严格模式和非严格模式之间的区别
- QNX平台下QT开发环境的配置
- git的学习二
- 国庆清北刷题冲刺班 Day4 上午
- test
- 结构体顺序表的创建、初始化、插入、按值查找、删除的代码
- Ecilpse卡死问题解决大全
- 关于LWIP在应用中遇到的一个问题memp_malloc: out of memory in pool TCP_PCB