精华内容
下载资源
问答
  • android 来电防火墙

    2011-01-16 23:23:51
    android 来电防火墙,有自定义黑名单,白名单功能. 功能已经实现,可以直接编译,API等级4. 调用了隐藏类来控制来电.. 结合SQLite,BroadcastReceiver... 布局里头用到了ListView+TabHost.. 适合新手学习
  • Android 来电监听

    千次阅读 热门讨论 2019-07-28 23:08:31
    最近刚接到一个需求,为BOSS做一个来电显示功能,查找号码库显示姓名角色。 一、查找来电监听方法 PhoneStateListener监听器类,用于监视设备上特定电话状态的变化,包括服务状态、信号强度、消息等待指示器(语音...

    最近刚接到一个需求,为BOSS做一个来电显示功能,查找号码库显示姓名角色。

    一、查找来电监听方法

    PhoneStateListener监听器类,用于监视设备上特定电话状态的变化,包括服务状态、信号强度、消息等待指示器(语音邮件)等。

    import android.telephony.PhoneStateListener;
    import android.telephony.TelephonyManager;
    import android.util.Log;
    
    public class MyPhoneStateListener extends PhoneStateListener {
        private static final String TAG = "MyPhoneStateListener";
        protected CallListener listener;
        /**
         * 返回电话状态
         *
         * CALL_STATE_IDLE 无任何状态时
         * CALL_STATE_OFFHOOK 接起电话时
         * CALL_STATE_RINGING 电话响铃时
         */
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE:
                    Log.d(TAG ,"电话挂断...");
                    listener.onCallIdle();
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    Log.d(TAG ,"正在通话...");
                    listener.onCallOffHook();
                    break;
                case TelephonyManager.CALL_STATE_RINGING:
                    Log.d(TAG ,"电话响铃...");
                    listener.onCallRinging();
                    break;
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    
        //回调
        public void setCallListener(CallListener callListener) {
            this.listener = callListener;
        }
    
        //回调接口
        public interface CallListener {
            void onCallIdle();
            void onCallOffHook();
            void onCallRinging();
        }
    }
    

    TelephonyManager 提供对设备上电话服务的信息的访问。应用程序可以使用该类中的方法来确定电话服务和状态,以及访问某些类型的订阅者信息。应用程序还可以注册侦听器来接收电话状态更改的通知。

    import android.content.Context;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.telephony.TelephonyManager;
    import com.flymbp.callmonitor.MyPhoneStateListener;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            telephony();
        }
    
        private void telephony() {
            //获得相应的系统服务
            TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            if(tm != null) {
                try {
                    MyPhoneStateListener myPhoneStateListener = new MyPhoneStateListener();
                    myPhoneStateListener.setCallListener(new MyPhoneStateListener.CallListener() {
                        @Override
                        public void onCallIdle() {
                        }
    
                        @Override
                        public void onCallOffHook() {
                        }
    
                        @Override
                        public void onCallRinging() {
                        //走接口查询号码信息
                        }
                    });
                    // 注册来电监听
                    tm.listen(myPhoneStateListener, MyPhoneStateListener.LISTEN_CALL_STATE);
                } catch(Exception e) {
                    // 异常捕捉
                }
            }
        }
    }
    

    此时此刻我们就可以监听到来电状态,但是incomingNumber没值,测试设备是华为mate20 pro Android 9.0
    需要READ_CALL_LOG权限

      	<!--读取电话的状态信息的权限-->
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <!--读取通话记录的权限-->
        <uses-permission android:name="android.permission.READ_CALL_LOG" />
    

    Android 9 来电监听incomingNumber为空

    拿到incomingNumber 我们就可以请求后台接口来获取号码信息,或者有本地号码数据库进行查找。

    二、来电弹窗提示信息

    来电号码信息有了,我们要在来电界面进行提示,既然不能对来电界面进行篡改,那我们就加个弹窗提示吧。
    想到两种方式:
    1、Toast提示,实现简单,但是显示时间短,不是主动触发,会错过看到提示,不采用。
    2、悬浮窗提示,既然要在自身应用以外的界面上显示弹窗,那必然要使用悬浮窗。

    我们将使用悬浮窗进行来电提示。为了让悬浮窗与Activity脱离,使其在应用处于后台时悬浮窗仍然可以正常运行,这里使用Service来启动悬浮窗。

    来电时显示悬浮窗,点击悬浮窗可移除,拖拽悬浮窗可移动,接通或挂断移除悬浮窗,注意悬浮窗不要来一个电话显示一个弹窗。

    public class FloatingButtonService extends Service {
        public static boolean isStarted = false;
    
        private WindowManager windowManager;
        private WindowManager.LayoutParams layoutParams;
    
        private Button button;
        private String content;
    
        @Override
        public void onCreate() {
            super.onCreate();
            isStarted = true;
            windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
            layoutParams = new WindowManager.LayoutParams();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            } else {
                layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
            }
            layoutParams.format = PixelFormat.RGBA_8888;
            layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
            layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            layoutParams.width = 500;
            layoutParams.height = 100;
            layoutParams.x = 300;
            layoutParams.y = 300;
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            content = intent.getStringExtra("content");
            int state = intent.getIntExtra("state", 0);
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE:
                    removeFloating();
                break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    removeFloating();
                break;
                case TelephonyManager.CALL_STATE_RINGING:
                    showFloatingWindow();
                break;
            }
            return super.onStartCommand(intent, flags, startId);
        }
    
        private void removeFloating() {
            if(button != null){
                windowManager.removeView(button);
            }
        }
    
        private void showFloatingWindow() {
            if(button != null){
                windowManager.removeView(button);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (Settings.canDrawOverlays(this)) {
                    button = new Button(getApplicationContext());
                    button.setText(content);
                    button.setTextColor(Color.BLACK);
                    button.setBackgroundColor(Color.WHITE);
                    button.setOnTouchListener(new FloatingOnTouchListener());
                    windowManager.addView(button, layoutParams);
                }
            } else {
                button = new Button(getApplicationContext());
                button.setText(content);
                button.setTextColor(Color.BLACK);
                button.setBackgroundColor(Color.WHITE);
                button.setOnTouchListener(new FloatingOnTouchListener());
                windowManager.addView(button, layoutParams);
            }
        }
    
        private class FloatingOnTouchListener implements View.OnTouchListener {
            private int x;
            private int y;
    
            private int clickx;
            private int clicky;
    
            @Override
            public boolean onTouch(View view, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        x = (int) event.getRawX();
                        y = (int) event.getRawY();
                        clickx = x;
                        clicky = y;
                        break;
                    case MotionEvent.ACTION_MOVE:
                        int nowX = (int) event.getRawX();
                        int nowY = (int) event.getRawY();
                        int movedX = nowX - x;
                        int movedY = nowY - y;
                        x = nowX;
                        y = nowY;
                        layoutParams.x = layoutParams.x + movedX;
                        layoutParams.y = layoutParams.y + movedY;
                        windowManager.updateViewLayout(view, layoutParams);
                        break;
                    case MotionEvent.ACTION_UP:
                        if (clickx == x && clicky == y)
                            windowManager.removeView(button);
                        break;
                    default:
                        break;
                }
                return false;
            }
        }
    }
    

    如何触发悬浮窗呢?

    BroadcastReceiver使用广播来接收来电状态

    在MainActivity.onCreate中注册广播

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
    	setContentView(R.layout.activity_main);
    	BroadcastReceiver mReceiver = new BroadcastReceiver() {
    	@Override
        public void onReceive(Context context, Intent intent) {
        	String data = intent.getStringExtra("data");
        	showFloating(data);
        	}
        };
        IntentFilter intentFilter = new IntentFilter("android.intent.action.MAIN");
        registerReceiver(mReceiver, intentFilter);
    }
    
    public void showFloating(String mobile, int state) {
    	Intent regIntent = new Intent(MainActivity.this, FloatingButtonService.class);
    	regIntent.putExtra("content", mobile);
    	regIntent.putExtra("state",state);
    	startService(regIntent);
    }
    

    三、后台监听

    来电监听我们不能总让应用在前台运行吧,这时需要后台运行进行监听。
    需要把在MainActivity.telephony的方法写到服务里。

    public class MyPhoneStateListenService extends Service {
        private static final String tag = "MyPhoneStateListenService";
        public static final String ACTION_REGISTER_LISTENER = "action_register_listener";
        // 电话管理者对象
        private TelephonyManager mTelephonyManager;
        // 电话状态监听者
        private MyPhoneStateListener myPhoneStateListener;
    
        @Override
        public void onCreate() {
            mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            myPhoneStateListener = new MyPhoneStateListener(this);
            mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
            super.onCreate();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public void onDestroy() {
            // 取消来电的电话状态监听服务
            if (mTelephonyManager != null && myPhoneStateListener != null) {
                mTelephonyManager.listen(myPhoneStateListener, PhoneStateListener.LISTEN_NONE);
            }
            super.onDestroy();
        }
    }
    

    在MainActivity.onCreate中开启服务

    private void registerPhoneStateListener() {
    	Intent intent = new Intent(this,  MyPhoneStateListenService.class);
    	intent.setAction(MyPhoneStateListenService.ACTION_REGISTER_LISTENER);
    	startService(intent);
    }
    

    四、进程保活

    那么问题又来了,在后台服务很容易被杀,那我们就得考虑加入保活方案。
    保活方案有很多,采用合适的方案,这里就不细说了。
    常见的一些保活方案:
    1、一像素保活
    2、双进程守护
    3、后台播放无声音乐
    。。。

    展开全文
  • Android 来电自动接听

    千次阅读 2017-10-10 15:20:52
    Android 来电自动接听、挂断。 今天闲来无事,刚好一个朋友需要做一个来电自动接听的功能,我一想,咦,这尼玛我还没做过,好吧,去看看!好吧,看就看吧那么我提来了,我该从哪儿入手呢?

    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 应用是关闭状态,也可以在应用中取到来电信息的。

    这很酷,是吧?现在让我们看看该 “怎么做” !

    关键点在于 Receiver

    你听说过 Android 里面的 receiver 么?

    如果听说过的话,那么你会很容易的弄清楚手机状态这个概念的。

    当然,没听说过也不要担心,我会告诉你 receiver 是什么以及如何在应用中使用它。

    RECEIVER 到底是个什么鬼东西?

    Broadcast receiver 帮助我们接收系统或其他应用的消息。

    Broadcast receiver 响应来自系统本身或其他应用的广播信息(intent、event等)。

    点击以下链接获取更多知识:

    在我们的应用里创建一个 Broadcast Receiver 需要执行以下两步:

    1. 创建 Broadcast Receiver
    2. 注册 Broadcast Receiver

    让我们先在 Android Studio 里建立一个带有空白 Activity 的简单工程。

    如果你第一次接触 Android studio 不知道如何创建新工程的话,点击以下链接:

    让我们创建并注册 BROADCAST RECEIVER

    创建一个名为 PhoneStateReceiver 的 Java 类文件,并继承 BroadcastReceiver 类。

    要注册 Broadcast Receiver的话,需要将以下代码写入 AndroidMainifest.xml 文件

    <receiver android:name=".PhoneStateReceiver">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
    </receiver>
    

    注意

    你必须在 <application>标签内写这几行代码.

    我们的主要目的是接收通话广播,所以我们需要将 android.intent.action.PHONE_STATE 作为 receiver 的 action。

    你的 AndroidMainifest.xml 文件应该和下图一样:

    Phone State Receiver

    漂亮!我们成功的在项目中加入了一个 Broadcast Receiver。

    你得到权限了么?

    为了在应用中接收手机的通话状态广播,你需要取得对应的权限。

    我们需要在 AndroidManifest.xml 文件中写入以下代码来获取权限。

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    

    现在你的 AndroidManifest.xml 应该和下面这张图一样了

    Read Phone State

    关于 onReceive() 方法的来龙去脉

    现在让我们将目光转回到 继承了 BroadcastReceiver 的 PhoneStateListener 类中。

    在这个类中我们需要重写 onReceive(Contex context, Intenet intent) 方法,因为在基类(BroadcastReceiver)中这个方法是抽象方法(abstract method)。

    你对 onReceive() 方法了解多少呢?

    如果我让你天马行空的想象一下这个方法的作用,你会怎么猜呢?

    提示: 它的名字已经解释了一切。

    加油……努力……你离答案只有一步之遥了……

    是的,就是你猜的那样。onReceive() 使用 Intent 对象参数来接收每个消息。我们已经声明并在 AndroidManifest.xml 中注册了Broadcast Receiver。

    现在,让我们将目光转向 PhoneStateReciver.java 文件来看看我们要在 onReceive() 方法中做些什么。

    public void onReceive(Context context, Intent intent) {
    
        try {
            System.out.println("Receiver start");
            Toast.makeText(context," Receiver start ",Toast.LENGTH_SHORT).show();
        }
        catch (Exception e){
            e.printStackTrace();
        }
    
    }
    

    我们已经做了一堆准备工作了,你觉得我们现在是不是可以检测到通话状态了呢?

    先自己想一想。

    目前只要收到来电就会弹出一个显示 Receiver start 消息的 toast,我们也会在控制台中收到同样的消息,因为我们已经将其输出到控制台中。 Receiver Start

    但……

    我们无法得知准确的通话状态,我们的目标是取到如下的状态:

    • 响铃
    • 摘机
    • 空闲

    保持冷静,继续探索手机状态

    那我们要怎么做来取到电话状态信息呢? 你听说过 Android 里面的 Telephony Manager 么?

    如果你对 Telephony Manager 不熟悉的话,别担心。我会教你什么是 Telephony Manager 以及如何用它取到通话状态的。

    Telephony Manager 会将来自 Android 设备电话的全部状态信息告诉你。利用这些状态我们可以做许多事。

    想了解更多关于 Telephony Manager 的知识,请点以下链接:

    我们可以通过 TelephonyManager.EXTRA_STATE 来取得当前通话状态。它会用一个 String 对象来返回当前通话状态。

    以如下方式新建一个 String 对象来获取不同的通话状态信息:

    String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
    

    要获取不同的状态,我们可以用下面的代码达到目的:

    if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
        Toast.makeText(context,"Ringing State Number is -"+incomingNumber,Toast.LENGTH_SHORT).show();
    }
    if ((state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))){
        Toast.makeText(context,"Received State",Toast.LENGTH_SHORT).show();
    }
    if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
        Toast.makeText(context,"Idle State",Toast.LENGTH_SHORT).show();
    }
    

    现在我们的 PhoneCallReceiver 类应该如下所示:

    Broadcast Receiver

    是的,我们成功了!!!

    我们成功达到了目标,你可以用模拟器或真机来检验一下成果。

    如果你不知道如何打开模拟器的话,按照下面的步骤来:

    1. 打开 Android studio
    2. 点击 Android Device Monitor。如果你找不到 Android Device Monitor 的话,看下面这张截图。

    Android Device Moniter

    下面这张图会显示如何操作模拟器

    Emulator Control

    如果你使用新版本的 Android Studio (2.1 +) 或者你有最新的 HAXM 那你要跟着下面这张图来

    Phone Device

    就酱。你可以用模拟器来监测通话状态了,下面的截图显示了运行结果。

    结果 1. 来电状态

    Incoming Call State

    结果 2. 接听状态

    Call Receiver State

    结果 3. 空闲状态

    Call Idle State

    我们的主要目标就完成了。

    需要来电号码?

    你仔细看过 Telephony Manager 这个类么?

    你看到 TelephonyManager.EXTRA_INCOMING_NUMBER 这个了么?

    如果你已经了解了 TelephonyManager.EXTRA_INCOMING_NUMBER,那很好,证明你读过我在上面给的关于 Telephony Manager 类的链接了

    TelephonyManager.EXTRA_INCOMING_NUMBER 用 String 的形式返回来电号码。

    Extra State

    String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
    

    如果你想在自己的应用中监测来电号码,可以利用下面的代码:

    public class PhoneStateReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
    
            try {
                String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
                String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
    
                if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
    
                    Toast.makeText(context,"Ringing State Number is - " + incomingNumber, Toast.LENGTH_SHORT).show();
                }
            }
            catch (Exception e){
                e.printStackTrace();
            }
    
        }
    

    啊哈!我们成功取到了来电号码!

    但愿本篇博客在获取来电信息方面对你有所帮助。对于获取来电消息方面还有问题的话请留言,我会尽快回复的。

    学习 Android 很棒,不是么?来看看其他的 Android 教程 吧。

    有开发 Android 应用的灵感?还等什么,快 联系我们 ,灵感直播即将上线。我们的公司被提名为印度最好的 Android 应用开发公司 。





    原文发布时间为:2016年11月06日

    本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。
    展开全文
  • 1.可以直接运行测试 2.android版本2.3.3 3.完美解决来电去电的事件. 4.获取到号码后弹出window 5.挂断后window消失
  • android 来电分析

    2012-12-29 15:11:51
    一个新来电是由CallNotifier监听到的,CallNotifier类继承与Handler,在CallNotifier.java里面,代表新来点的Message是PHONE_NEW_RINGING_CONNECTION。 mPhone.registerForNewRingingConnection(this, PHONE_NEW_...

    一个新来电是由CallNotifier监听到的,CallNotifier类继承与Handler,在CallNotifier.java里面,代表新来点的Message是PHONE_NEW_RINGING_CONNECTION。

    mPhone.registerForNewRingingConnection(this, PHONE_NEW_RINGING_CONNECTION, null);

    当然,得注册这个信号。有新来电时,CallNotifier收到这个新号,交由onNewRingingConnection((AsyncResult) msg.obj)来处理

    在onNewRingingConnection()内,

    boolean provisioned = Settings.Secure.getInt(mPhone.getContext().getContentResolver(),
                Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
    查询是否设置了拒接电话,如果是,则直接挂断电话。然后,设置音频为响铃状态,通过startIncomingCallQuery(Connection c)开始查询来电信息。

    在startincomingCallQuery()里面,先判定是否能查询,如果不是,直接启动来电界面,否则,继续查询来电人的信息,比如对应铃声等,查询完以后,启动来电界面,即调用displayCallScreen();

    启动来电界面以后,电话控制权就完全交由InCallScreen.java, 但是到现在为止,电话还是没有接通,只是通知了有来电,这就是,CallNotifier.java完成的任务,跟他的名字一样,只是起到Notify的作用。在来电界面,InCallScreen.java监听用户的Key Event, 如果按下的是接听键,则接听电话,如果是挂机键,就挂断电话。

    按下接听键, CallNotifier会收到一个PHONE_STATE_CHANGED的信号,如果按下,挂机键,会收到一个PHONE_STATE_DICONNECT,如果接听,则设置音频状态为接听电话状态,停止响铃,放置一个接电话的图标在屏幕上,与此同时,InCallScreen也会收到这样一个新号,它做的事情就是更新通话界面,比如点亮屏幕,使菜单消失等等。 但是如果挂断电话,那做的是就是更新通话记录,停止响铃等。

    展开全文
  • 原标题:谷歌正式公布...谷歌通过LG G Watch展示了Android Wear可以做些什么,简单来说Android Wear就是一个连通多平台之间的系统,可以同步平板和手机的智能提醒信息,并对手机、平板等设备进行操控。当手机接到...
  • Android N 来电界面

    千次阅读 2017-01-11 15:51:43
    本流程图基于MTK平台 Android N,普通来电,本流程只作为沟通学习使用通过前面 Android 7.0 Phone_MT来电流程 的流程分析中我们可以发现,最后是将来电信息和状态传送到了 dialer 的 incallUI 里面,在 ...
  • Android系统获取用户来电信息

    千次阅读 2016-07-19 22:25:45
    因为我们只想获取来电信息,所以加入判断,当电话状态为TelephonyManager.CALL_STATE_RINGING 时我们才将获取到的电话进行显示。 然后,为了更加的便利,我们加入getContactNameFromPhoneBook() 方法...
  •  对于来电如何拦截,我们想象一下要拦截来电,首先我们的必须知道,有没有电话打进来,只有确定来了电话,我们才好去拦截,就像战斗中拦截导弹一样,没有雷达去捕获来袭导弹的信息,那就没法拦
  • 我觉得写文章就得写得有用一些的,必须要有自己的思想,关于来电去电监听将按照下面三个问题展开 1、监听来电去电有什么用? 2、怎么监听,来电去电监听方式一样吗? 3、实战,有什么需要特别注意地方? 一、...
  • android来电知了

    千次阅读 2012-04-13 18:17:15
    这周做了一个来电知了的项目,具体需求如下: 1.可以设置黑名单号码,拒接电话和短信 2.来电归属地查询 在生活中我们用到这些东西的时候感觉挺简单,但是让我们实现这些功能时,还是非常麻烦的。下面是我在...
  • Android 7.0模拟来电

    千次阅读 2018-11-05 14:09:05
    Android 7.0模拟来电 一、写作目的 有时为了测试的需要,在没SIM卡的机器上测试来电,需要一种一种模拟技术。这篇文章***模拟来电的实现***给出了实现的方式,但说的比较概要。本篇文章则根据自己的实践步骤整理而...
  • android9.0来电无法获取处理

    千次阅读 2019-01-04 11:13:56
    https://developer.android.com/about/versions/pie/android-9.0-changes-all?hl=zh-cn 这个连接说了。android 必须添加新权限,官网说: 限制访问电话号码 在未首先获得 READ_CALL_LOG 权限的情况下,除了应用的...
  • 来电呼入时的各种信息显示都是在CallCard.java中实现的,其中的updateDisplayForPerson是主角。updateDisplayForPerson会根据电话的当前状态来更改名字号码等信息的显示。图片的替换代码如下: ContactsAsyncHelper...
  • Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声 一、Android来电铃声默认设置的实现方法 Andoird默认来电铃声的设置方法为修改build/target/product/core.mk的ro.config.ringtone的值如 ro....
  • 一:拦截来电的功能实现  现在的Android版本已经把Phone类的相关API给隐藏起来了,想要用代码实现挂断电话的功能,就必须通过AIDL才行,然后利用反射来使用其方法。  1:在程序中新建一个包,因为要使用aidl,...
  • MissedCallAlarmAndroid Android应用程序,用于通过短信获取远程智能手机上的未接来电信息 此应用程序使用 Android Froyo(2.2v) 设计,不保证针对最新的 Android 版本进行优化工作。
  • Android 监听手机来电

    2019-04-08 13:19:53
    这里我只写用着的方案 首先是权限问题: ...uses-permission android:name="android.permission.READ_PHONE_STATE" />--> <!--处理拨出电话,允许程序监视,修改或放弃播出电话--> <u...
  • Android电话来电流程源码分析

    千次阅读 2013-08-21 10:50:18
    Android的Phone设计的相当复杂,只有了解了Phone的设计框架才能把握电话的拨号或来电流程,在Android电话...Framework层的RIL中的RILReceiver线程从rild服务进程中读取modem发送上来的来电消息等信息,通过消息注册-响
  • Android TelecomService的来电处理过程

    千次阅读 2017-03-03 12:13:48
    在上一篇文章里,讲到了TelecomService的启动与初始化,这里我们着重以来电(Mobile Terminal)过程来分析一下TelecomService是如何传递通话信息并最终与上层UI交互的。...TelecomService如何告知UI来电信息

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,224
精华内容 3,689
关键字:

android来电信息