精华内容
下载资源
问答
  • android来电秀demo

    2019-03-28 14:51:36
    android来电弹窗小demo,可以自定义窗体大小等。android好用的来电秀。
  • 主要为大家详细介绍了Android来电拦截的实现方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • android来电拒接Demo

    2015-03-11 11:49:11
    android来电拒接Demo,通过监听来电广播来挂断电话。
  • 自己做的Android来电接听界面,可以左右滑动接听或者挂断源码 自己做的Android来电接听界面,可以左右滑动接听或者挂断源码
  • android 来电系统广播

    2015-04-26 02:49:03
    android来电的系统广播是什么,还是说只有电话状态改变的广播
  • 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 来电监听

    千次阅读 热门讨论 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-04-24 13:49:44
    Android 来电悬浮框的探索基于项目中需要,监听系统来电弹出自定义的悬浮框,综合其他博主共享的资源,成功在项目中实现了这一功能。本着达则兼济天下的崇高理想,分享出来,以供参阅。开始之前推荐一篇关于悬浮框...

    Android 来电悬浮框的探索

    基于项目中需要,监听系统来电弹出自定义的悬浮框,综合其他博主共享的资源,成功在项目中实现了这一功能。本着达则兼济天下的崇高理想,分享出来,以供参阅。开始之前推荐一篇关于悬浮框层级的博文:浮窗开发层级问题

    根据需求我把整个功能分割了以下几个部分:

    • 监听系统来电的广播
    • 接收广播处理通话状态
    • 悬浮框界面
    • 接听功能实现
    • 挂断功能实现

    监听系统来电的广播

    AndroidManifest.xml中注册监听系统来电的广播之前需要添加权限:

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

    注册广播:

    <receiver android:name="com.softi.cs.ui.receiver.CSCallReceiver" >
    <intent-filter>
     <action android:name="android.intent.action.PHONE_STATE" />
     <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
     <action android:name="call.cs.call.ending.action" />
    </intent-filter>
    </receiver>

    接收广播处理通话状态

    接收广播的类:CSCallReceiver .java

    public class CSCallReceiver extends BroadcastReceiver {
    
        private Context mContext;
        private boolean incomingFlag=false;
        private String incoming_number="";
        private String TAG="CSCallReceiver";
        private String phoneNumber;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            mContext = context;
            TelephonyManager sTelephoneyManager = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
    
            //如果是拨打电话  
            if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){ //外呼不做处理                       
                    incomingFlag = false;  
                    phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);          
                    Log.i(TAG, "call OUT:"+phoneNumber);                          
            }else if(intent.getAction().equals("call.cs.call.ending.action")){//处理挂断,在PhoneActivity接收广播 并延时4秒关闭界面,为了遮盖系统电话关闭页面
    
                sendCloseBroadCast();
    
            }else{                          
                    //如果是来电  ,开启悬浮页面。
                    TelephonyManager tm =   
                        (TelephonyManager)context.getSystemService(Service.TELEPHONY_SERVICE);                          
    
                    switch (tm.getCallState()) {  
                    case TelephonyManager.CALL_STATE_RINGING:  
                            incomingFlag = true;//标识当前是来电  
                            incoming_number = intent.getStringExtra("incoming_number");  
                            Intent myIntent =new Intent(context,PhoneActivity.class);
                            myIntent.putExtra("incoming_number", incoming_number);
                            myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            context.startActivity(myIntent);
                            Log.i(TAG, "RINGING :"+ incoming_number);  
                            break;  
                    case TelephonyManager.CALL_STATE_OFFHOOK:                                  
                            if(incomingFlag){  
                                    Log.i(TAG, "incoming ACCEPT :"+ incoming_number);  
                            }  
                            break;  
    
                    case TelephonyManager.CALL_STATE_IDLE:                                  
                            if(incomingFlag){  
                                    Log.i(TAG, "incoming IDLE");                                  
                            }  
                            break;  
                    }   
            }  
    
        }
    
    private void sendCloseBroadCast() {
                                                                    Intent intent = new  Intent("com.chinasofti.rcs.finishcall");
    mContext.sendBroadcast(intent);
        }
    
    
    }
    

    悬浮框界面

    收到来电广播,弹出悬浮框界面:PhoneActivity.java

    public class PhoneActivity extends Activity implements OnClickListener {
        private MyBroadcastReceiver mBroadcastReceiver;
    
        public static int OVERLAY_PERMISSION_REQ_CODE = 1234;
    
        private static final String LOG_TAG = "PhoneActivity";
        private static View mView = null;
        private static WindowManager mWindowManager = null;
        private static Context mContext = null;
        public static Boolean isShown = false;
        TelephonyManager telMgr;
    
        private Button declinButton;
    
        private Button answerButton;
        private static final String MANUFACTURER_HTC = "HTC";
    
        private AudioManager audioManager;
    
        private ImageView incomingThumb;
    
        private TextView callName;
    
        private String phoneNumber;
    
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                int what = msg.what;
                if (what == 0) {
                    hidePopupWindow();
                } 
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.layout_cs_main);
            Intent intent = getIntent();
            phoneNumber = intent.getStringExtra("incoming_number");
            mBroadcastReceiver = new MyBroadcastReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("com.chinasofti.rcs.finishcall");
            registerReceiver(mBroadcastReceiver, intentFilter);
            telMgr = (TelephonyManager) this.getSystemService(Service.TELEPHONY_SERVICE);
            audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
            askForPermission();
        }
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
        }
    
        @Override
        protected void onPause() {
            // TODO Auto-generated method stub
            super.onPause();
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(mBroadcastReceiver);
        }
    
        public class MyBroadcastReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(Context context, Intent intent) {
                Log.i(LOG_TAG, "MyBroadcastReceiver onReceive ");
                handler.sendEmptyMessageDelayed(0, 4000);
            }
        }
    
    
        /**
         * 请求用户给予悬浮窗的权限
         */
        public void askForPermission() {
            if (!Settings.canDrawOverlays(this)) {
                Toast.makeText(PhoneActivity.this, "当前无权限,请授权!", Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
            } else {
                showPopupWindow();
            }
        }
    
    
    
        /**
         * 显示弹出框
         *
         * @param context
         * @param view
         */
        public void showPopupWindow() {
            if (isShown) {
                Log.i(LOG_TAG, "return cause already shown");
                return;
            }
            isShown = true;
            Log.i(LOG_TAG, "showPopupWindow");
            // 获取应用的Context
            mContext = this.getApplicationContext();
            // 获取WindowManager
            mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
            mView = setUpView(this);
    
            WindowManager.LayoutParams params = new WindowManager.LayoutParams();
            // 类型
            params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
            // WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
            // 设置flag
            int flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
            // int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
            // | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
            // 如果设置了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,弹出的View收不到Back键的事件
            params.flags = flags;
            // 不设置这个弹出框的透明遮罩显示为黑色
            params.format = PixelFormat.TRANSLUCENT;
            // FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口
            // 设置 FLAG_NOT_FOCUSABLE 悬浮窗口较小时,后面的应用图标由不可长按变为可长按
            // 不设置这个flag的话,home页的划屏会有问题
            params.width = LayoutParams.MATCH_PARENT;
            params.height = LayoutParams.MATCH_PARENT;
            params.gravity = Gravity.CENTER;
            mWindowManager.addView(mView, params);
            Log.i(LOG_TAG, "add view");
        }
    
        /**
         * 隐藏弹出框
         */
        public void hidePopupWindow() {
            Log.i(LOG_TAG, "hide " + isShown + ", " + mView);
            if (isShown && null != mView) {
                Log.i(LOG_TAG, "hidePopupWindow");
                mWindowManager.removeView(mView);
                isShown = false;
                this.finish();
            }
        }
    
        private View setUpView(Context context) {
            Log.i(LOG_TAG, "setUp view");
            View view = LayoutInflater.from(context).inflate(R.layout.layout_cs_incomming, null);
            declinButton = (Button) view.findViewById(R.id.call_cs_decline);
            answerButton = (Button) view.findViewById(R.id.call_cs_answer);
            incomingThumb = (ImageView) view.findViewById(R.id.cs_incoming_thumb);
            callName = (TextView)view.findViewById(R.id.cs_call_name);
            declinButton.setOnClickListener(this);
            answerButton.setOnClickListener(this);
            //loadPhotoAndName();加载用户头像,和名称
            return view;
        }
    
    
        @Override
        public void onClick(View v) {
    
            switch (v.getId()) {
                case R.id.call_cs_decline:
                    telEndCall();
                    handler.sendEmptyMessageDelayed(0, 4000);
                    break;
                case R.id.call_cs_answer:
                     acceptCall();
                    break;
    
                default:
                    break;
            }
        }
    
        private void telEndCall() {
            Class<TelephonyManager> c = TelephonyManager.class;
            try {
                Method getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[]) null);
                getITelephonyMethod.setAccessible(true);
                ITelephony iTelephony = null;
                iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[]) null);
                iTelephony.endCall();
            } catch (Exception e) {
                Log.e(LOG_TAG, "Fail to answer ring call.", e);
            }
        }
    
        public void acceptCall() {
            try {
                Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
                IBinder binder = (IBinder) method.invoke(null, new Object[] { Context.TELEPHONY_SERVICE });
                ITelephony telephony = ITelephony.Stub.asInterface(binder);
                telephony.answerRingingCall();
            } catch (Exception e) {
                Log.e(LOG_TAG, "for version 4.1 or larger");
                acceptCall_4_1();
            }
        }
    
        public void acceptCall_4_1() {
            // 模拟无线耳机的按键来接听电话
            // for HTC devices we need to broadcast a connected headset
            boolean broadcastConnected = MANUFACTURER_HTC.equalsIgnoreCase(Build.MANUFACTURER) && !audioManager.isWiredHeadsetOn();
            if (broadcastConnected) {
                broadcastHeadsetConnected(false);
            }
            try {
                try {
                    Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
                } catch (IOException e) {
                    // 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));
                    this.sendOrderedBroadcast(btnDown, enforcedPerm);
                    this.sendOrderedBroadcast(btnUp, enforcedPerm);
                }
            } finally {
                if (broadcastConnected) {
                    broadcastHeadsetConnected(false);
                }
            }
        }
    
        private void broadcastHeadsetConnected(boolean connected) {
            Intent i = new Intent(Intent.ACTION_HEADSET_PLUG);
            i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
            i.putExtra("state", connected ? 1 : 0);
            i.putExtra("name", "mysms");
            try {
                this.sendOrderedBroadcast(i, null);
            } catch (Exception e) {
            }
        }
        /**
         * 用户返回
         * 
         * @param requestCode
         * @param resultCode
         * @param data
         */
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode == OVERLAY_PERMISSION_REQ_CODE) {
                if (!Settings.canDrawOverlays(this)) {
                    Toast.makeText(PhoneActivity.this, "权限授予失败,无法开启悬浮窗", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(PhoneActivity.this, "权限授予成功!", Toast.LENGTH_SHORT).show();
                    showPopupWindow();
                }
    
            }
        }   
    }
    

    接听功能实现

    接听和挂断功能来源于其他博主

    public void acceptCall() {
            try {
                Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
                IBinder binder = (IBinder) method.invoke(null, new Object[] { Context.TELEPHONY_SERVICE });
                ITelephony telephony = ITelephony.Stub.asInterface(binder);
                telephony.answerRingingCall();
            } catch (Exception e) {
                Log.e(LOG_TAG, "for version 4.1 or larger");
                acceptCall_4_1();
            }
        }
    
        public void acceptCall_4_1() {
            // 模拟无线耳机的按键来接听电话
            // for HTC devices we need to broadcast a connected headset
            boolean broadcastConnected = MANUFACTURER_HTC.equalsIgnoreCase(Build.MANUFACTURER) && !audioManager.isWiredHeadsetOn();
            if (broadcastConnected) {
                broadcastHeadsetConnected(false);
            }
            try {
                try {
                    Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
                } catch (IOException e) {
                    // 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));
                    this.sendOrderedBroadcast(btnDown, enforcedPerm);
                    this.sendOrderedBroadcast(btnUp, enforcedPerm);
                }
            } finally {
                if (broadcastConnected) {
                    broadcastHeadsetConnected(false);
                }
            }
        }

    挂断功能实现

    private void telEndCall() {
            Class<TelephonyManager> c = TelephonyManager.class;
            try {
                Method getITelephonyMethod = c.getDeclaredMethod("getITelephony", (Class[]) null);
                getITelephonyMethod.setAccessible(true);
                ITelephony iTelephony = null;
                iTelephony = (ITelephony) getITelephonyMethod.invoke(telMgr, (Object[]) null);
                iTelephony.endCall();
            } catch (Exception e) {
                Log.e(LOG_TAG, "Fail to answer ring call.", e);
            }
        }
    
    展开全文
  • Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声  Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声  一、Android来电铃声默认设置的实现方法  Andoird默认来电铃声的设置方法...
    Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声

      Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声

      一、Android来电铃声默认设置的实现方法

      Andoird默认来电铃声的设置方法为修改build/target/product/core.mk的ro.config.ringtone的值如

      ro.config.ringtone=Backroad.ogg,该音乐文件必须于framework/base/data/sounds/Android.mk中加入音乐文件。

      framework/base/media/java/android/media/MediaScanner.java中类的初始化时会设置默认铃声的文件名的变量mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + Setting.System.RINGTONE);

      MediaScanner该类会搜索音乐文件必插入数据库中,搜索过程中检查是否与设置的默认铃声相同,如果相同则设为默认铃声。

      } else if (ringtones && mWasEmptyPriorToScan && !mDefaultRingtoneSet) {
                    if (TextUtils.isEmpty(mDefaultRingtoneFilename) ||
                            doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) {
                        setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId);
                        setProfileSettings(AudioProfileManager.TYPE_RINGTONE, tableUri, rowId);
                        mDefaultRingtoneSet = true;
                    }
                }

      二、如何设置语音来电的默认铃声

      首先在core.mk中新增ro.config.videocall=BentleyDubs.ogg。

      在framework/base/media/java/android/media/MediaScanner.java类中新加两个成员变量

    private boolean mDefaultVideoCallSet;

      private String mDefaultVideoCallFilename;

      在setDefaultRingtoneFileNames()方法中加入以下代码初始化默认铃声的文件名

            mDefaultVideoCallFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX
                    + Settings.System.VIDEO_CALL);

      在endFile()方法中加入以下代码设置语音来电的默认铃声

      
                } else if (ringtones && mWasEmptyPriorToScan && !mDefaultVideoCallSet) {
                    if (TextUtils.isEmpty(mDefaultVideoCallFilename) ||
                            doesPathHaveFilename(entry.mPath, mDefaultVideoCallFilename)) {
                        setSettingIfNotSet(Settings.System.VIDEO_CALL, tableUri, rowId);
                        setProfileSettings(AudioProfileManager.TYPE_VIDEO_CALL, tableUri, rowId);
                        mDefaultVideoCallSet = true;
                    }
                }

    展开全文
  • Android来电号码获取代码

    千次阅读 2010-11-10 00:02:00
    Android来电号码获取的方法很简单,虽然Dalvik上的程序都是Java写的,但是仍然可以处理系统事物,使用PhoneStateListener;类可以监测话机状态,而TelephonyManager可以获取电话服务的实例,写代码时不要忘了 在...
  • android 来电自动接听和自动挂断     注意:android2.3版本不支持下面的自动接听方法。(会抛异常:java.lang.SecurityException: Neither user xxxxx nor current process has android.permission.MODIFY_...
  • Android来电监听

    千次阅读 2013-09-04 11:08:58
    实现来电自动接听,自动录音,自动回拨功能。
  • Android来电管理

    2013-07-03 21:30:35
    1. 挂断电话 try { //反射获得系统服务的getService方法对象 Method method = Class.forName("android.os.ServiceManager") .getMethod("getService", String
  • Android来电铃声默认设置的实现方法与如何设置语音来电的默认铃声 一、Android来电铃声默认设置的实现方法 Andoird默认来电铃声的设置方法为修改build/target/product/core.mk的ro.config.ringtone的值如 ro....
  • android 来电自动接听和自动挂断     注意:android2.3版本不支持下面的自动接听方法。(会抛异常:java.lang.SecurityException: Neither user xxxxx nor current process has android.permission.MO
  • Android来电铃声播放机制应该是这样的: 铃声播放程序启动后应该会先判断当前是否设置了静音或者音量为0,如果为0或者静音的话,则不播放,来电铃声播放的程序就直接结束了。
  • android 来电分析

    2012-12-29 15:11:51
    一个新来电是由CallNotifier监听到的,CallNotifier类继承与Handler,在CallNotifier.java里面,代表新来点的Message是PHONE_NEW_RINGING_CONNECTION。 mPhone.registerForNewRingingConnection(this, PHONE_NEW_...
  • Telecomm\Service\src\com\android\server\telecom\ParcelableCallUtils.java 单卡情况下,来电界面都是有短信拒接的; 双卡时,来电的情况下,来电卡是确定的,如果要短信拒接的话,那也只能将短信发送到来电的那...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 15,719
精华内容 6,287
关键字:

android来电