参考:android 来电接听和挂断 支持目前所有版本

注意:android2.3版本及以上不支持下面的自动接听方法。

(会抛异常:java.lang.SecurityException: Neither user xxxxx nor current process has android.permission.MODIFY_PHONE_STATE.)

原因:android2.3版本及以上android.permission.MODIFY_PHONE_STATE权限限制已经改为系统权限。

普通应用程序已经无法调用,所以网上找到的那些如何使用android.permission.MODIFY_PHONE_STATE的文章均已失效,但仍有引用的办法就是让你的程序程序系统程序。一种就是预制到ROM中,另一种就是使用系统签名。第一种我已经试验通过,第二种还有待验证。

http://kongweile.iteye.com/blog/1428033

言归正传,先说下如何使用映射机制实现自动接听和挂断。

第一步:准备应用环境需要的系统包和aidl文件。

(1)在应用中创建包:android.telephony

将android系统框架下的\framework\telephony\java\android\telephony目录中的NeighboringCellInfo.aidl文件复制到上面创建的包(android.telephony )中;

(2)在应用中创建包:com.android.internal.telephony

将android系统框架下的\framework\telephony\java\com\android\internal\telephony目录中的ITelephony.aidl文件复制到上面创建的包(com.android.internal.telephony )中;

第二步:创建一个获取ITelephony的方法

PhoneUtils.java
Java代码
package com.zhouzijing.android.demo;

import java.lang.reflect.Method;
import com.android.internal.telephony.ITelephony;
import android.telephony.TelephonyManager;

public class PhoneUtils {

public static ITelephony getITelephony(TelephonyManager telephony) throws Exception {
Method getITelephonyMethod = telephony.getClass().getDeclaredMethod("getITelephony");
getITelephonyMethod.setAccessible(true);//私有化函数也能使用
return (ITelephony)getITelephonyMethod.invoke(telephony);
}
}

第三步:创建电话广播拦截器

MyPhoneBroadcastReceiver.java
Java代码
package com.zhouzijing.android.demo;

import com.android.internal.telephony.ITelephony;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

public class MyPhoneBroadcastReceiver extends BroadcastReceiver {

private final static String TAG = MyPhone.TAG;

@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "[Broadcast]"+action);

//呼入电话
if(action.equals(MyPhone.B_PHONE_STATE)){
Log.i(TAG, "[Broadcast]PHONE_STATE");
doReceivePhone(context,intent);
}
}

public void doReceivePhone(Context context, Intent intent) {
String phoneNumber = intent.getStringExtra(
TelephonyManager.EXTRA_INCOMING_NUMBER);
TelephonyManager telephony = (TelephonyManager)context.getSystemService(
Context.TELEPHONY_SERVICE);
int state = telephony.getCallState();

switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.i(TAG, "[Broadcast]等待接电话="+phoneNumber);
try {
ITelephony iTelephony = PhoneUtils.getITelephony(telephony);
iTelephony.answerRingingCall();//自动接通电话
//iTelephony.endCall();//自动挂断电话
} catch (Exception e) {
Log.e(TAG, "[Broadcast]Exception="+e.getMessage(), e);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.i(TAG, "[Broadcast]电话挂断="+phoneNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i(TAG, "[Broadcast]通话中="+phoneNumber);
break;
}
}

}

第四部:注册电话广播拦截器

MyPhone.java
Java代码
package com.zhouzijing.android.demo;

import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;

public class MyPhone extends Activity {
public final static String TAG = "MyPhone";

public final static String B_PHONE_STATE = TelephonyManager.ACTION_PHONE_STATE_CHANGED;

private MyPhoneBroadcastReceiver mBroadcastReceiver;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_phone);
}

//按钮1-注册广播
public void registerThis(View v) {
Log.i(TAG, "registerThis");
mBroadcastReceiver = new MyPhoneBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(B_PHONE_STATE);
intentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(mBroadcastReceiver, intentFilter);
}

//按钮2-撤销广播
public void unregisterThis(View v) {
Log.i(TAG, "unregisterThis");
unregisterReceiver(mBroadcastReceiver);
 }
 }

第5步:在AndroidManifest.xml配置权限
Xml代码
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
其中:
Java代码
iTelephony.answerRingingCall();//自动接通电话

必须有权限 android.permission.MODIFY_PHONE_STATE

Java代码
iTelephony.endCall();//自动挂断电话

必须有权限 android.permission.CALL_PHONE

因为Android2.3以上增加了对permission android.permission.MODIFY_PHONE_STATE 的限制,2.3之前的通过反射机制调用ITelephone的能力的做法已经不适用。
2.3上实现方式:
public synchronized void answerRingingCall() {

查询系统PhoneAPP应用(PhoneGlobals.java)实现了对耳机插入、多媒体按键等通知的接受和处理。其中未发现有特殊的地方,个人认为,如果系统接收到此广播应该可以进行接听或挂断操作。

private void answerRingingCallWithBroadcast(Context context,TelephonyManager telmanager){  
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);  
        //判断是否插上了耳机  
        if (! audioManager.isWiredHeadsetOn()) {

//4.1以上系统限制了部分权限, 使用三星4.1版本测试提示警告:Permission Denial: not allowed to send broadcast android.intent.action.HEADSET_PLUG from pid=1324, uid=10017

//这里需要注意一点,发送广播时加了权限“android.permission.CALL_PRIVLEGED”,则接受该广播时也需要增加该权限。但是4.1以上版本貌似这个权限只能系统应用才可以得到。测试的时候,自定义的接收器无法接受到此广播,后来去掉了这个权限,设为NULL便可以监听到了。

if(android.os.Build.VERSION.SDK_INT >=15 ){
                Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);  
                KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);  
                meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT,keyEvent);  
                context.sendOrderedBroadcast(meidaButtonIntent, null);  
        }else{

// 以下适用于Android2.3及2.3以上的版本上 ,但测试发现4.1系统上不管用。
        Intent localIntent1 = new Intent(Intent.ACTION_HEADSET_PLUG);  
                localIntent1.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);  
                localIntent1.putExtra("state", 1);  
                localIntent1.putExtra("microphone", 1);  
                localIntent1.putExtra("name", "Headset");  
                context.sendOrderedBroadcast(localIntent1,  "android.permission.CALL_PRIVILEGED");  
                
                Intent localIntent2 = new Intent(Intent.ACTION_MEDIA_BUTTON);  
                KeyEvent localKeyEvent1 = new KeyEvent(KeyEvent.ACTION_DOWN,  KeyEvent.KEYCODE_HEADSETHOOK);  
                localIntent2.putExtra(Intent.EXTRA_KEY_EVENT,   localKeyEvent1);  
                context. sendOrderedBroadcast(localIntent2,  "android.permission.CALL_PRIVILEGED"); 
                
                Intent localIntent3 = new Intent(Intent.ACTION_MEDIA_BUTTON);  
                KeyEvent localKeyEvent2 = new KeyEvent(KeyEvent.ACTION_UP,  KeyEvent.KEYCODE_HEADSETHOOK);  
                localIntent3.putExtra(Intent.EXTRA_KEY_EVENT,  localKeyEvent2);  
                context.sendOrderedBroadcast(localIntent3,  "android.permission.CALL_PRIVILEGED");  
                
                Intent localIntent4 = new Intent(Intent.ACTION_HEADSET_PLUG);  
                localIntent4.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);  
                localIntent4.putExtra("state", 0);  
                localIntent4.putExtra("microphone", 1);  
                localIntent4.putExtra("name", "Headset");  
                context.sendOrderedBroadcast(localIntent4, "android.permission.CALL_PRIVILEGED");
        }
              
        } else {  
            Intent meidaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);  
            KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);  
            meidaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT,keyEvent);  
            context.sendOrderedBroadcast(meidaButtonIntent, null);  
        }  
    }

android 接听和挂断实现方式的更多相关文章

  1. Android接听、挂断电话

    新建一个名为ITelephony的aidl文件,注意包名不能改变,因为是通过反射方式来实现接听和挂断的

  2. Android 电话自己主动接听和挂断具体解释

    1.通过aidl及反射实现挂断电话 详细分三步: (1)ITelephony.aidl ,必须新建com.android.internal.telephony包并放入ITelephony.aidl文件 ...

  3. Android 实现自动接听和挂断电话功能

    添加权限 <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permis ...

  4. Android 对电话进行监听和挂断

    1.添加权限 <!--拨打电话的权限--><uses-permission android:name="android.permission.PROCESS_OUTGOIN ...

  5. Android开发之通过反射获取到挂断电话的API

    Android开发黑名单工具类,需要用到挂断电话的API,但是该API处于隐藏状态,需要通过反射得到该方法.. 步骤: 1.通过当前类获取到ServiceManager的字节码 Class< ? ...

  6. android 自己主动拒接后再取消自己主动拒接,该联系人来电界面无图标显示,且点击挂断无反应

    1.    设置一个联系人为自己主动拒接 2.    该联系人来电 3.    取消该联系人的自己主动拒接 4.    该联系人来电 Error: 来电界面无头像显示,直接显示黑屏,且点击拒接butt ...

  7. 内容观察者 ContentObserver 监听短信、通话记录数据库 挂断来电

    Activity public class MainActivity extends ListActivity {     private TextView tv_info;     private  ...

  8. Android7.0 Phone应用源码分析(四) phone挂断流程分析

    电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...

  9. Ubuntu或linux 运行后台进程运行不挂断的办法

    nohup python ChatReq.py 20000 >>log_cronjob.txt 2>&1 & 之前把nohup去掉,发现就算运行python Chat ...

随机推荐

  1. Asp.net 主题 【2】

    通常我们经常看到网页,一些软件提供换肤功能,各种主题间切换.ASP.NET 2.0 中可以用Theme和skin以及CSS轻松实现这个功能. 首先简单介绍一下三种技术:主题(Theme)技术,面板(s ...

  2. 低字节序和高字节序相互转换(Little Endian/Big Endian)

    这个例子展示了如何转换整形数字的字节顺序,该方法可以用来在little-endian和big-endian之间转换. 说明:Windos(x86,x64)和Linux(x86,x64)都是little ...

  3. IDEA14下配置SVN

    本来以为是很简单的事情,没想到也浪费我有一会的时间,中间也出现了多多少少的问题. 1.在官网下载SVN,版本要为1.8,切忌不能1.9,否则会出错. 在安装SVN的时候,不能一路下一步,我们要安装命令 ...

  4. 解决jQuery插件sliderjs, 点击插件分页,导航按钮后不能重新开始.

    jQuery SlidesJS - Can't restart animation after clicking on navigation or pagination <!DOCTYPE ht ...

  5. ActiveReports 交互式报表之向下钻取解决方案

    在 ActiveReports 中可以动态的显示或者隐藏某区域的数据,通过该功能用户可以根据需要显示或者隐藏所关心的数据,结合数据排序.过滤等功能可以让用户更方便地分析报表数据. 本文中展示的是销售数 ...

  6. iPhone 6 图像渲染揭秘(转)

    几天前,Apple发布了iPhone 6 Plus. 新的iPhone大幅改变了图像在屏幕上渲染的方式.我们做了一个图表进行详细分析. 分析. 转自:转送

  7. 理解angularJS中作用域$scope

    angularJS中作用域是什么 作用域(scope)是构成angularJS应用的核心基础,在整个框架中都被广泛使用,因此了解它如何工作是非常重要的 应用的作用域是和应用的数据模型相关联的,同时作用 ...

  8. gulpfile的结构

    使用了      yargs     用于获取启动参数,针对不同参数,切换任务执行过程时需要,本项目中的useCache和useSess      path     不明,貌似是用来将某个目录中的文件 ...

  9. memcache锁

    锁的使用,一般情况是针对并发或者我们希望程序(crontab的job)串行处理,我们加锁的办法有很多,像文件锁,数据库锁,或者memcache锁,这里关注一下memcache锁,针对memcache锁 ...

  10. 10个重要的Linux ps命令实战

    Linux作为Unix的衍生操作系统,Linux内建有查看当前进程的工具ps.这个工具能在命令行中使用. PS 命令是什么 查看它的man手册可以看到,ps命令能够给出当前系统中进程的快照.它能捕获系 ...