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

原创粉丝点击