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 接听和挂断实现方式的更多相关文章
- Android接听、挂断电话
新建一个名为ITelephony的aidl文件,注意包名不能改变,因为是通过反射方式来实现接听和挂断的
- Android 电话自己主动接听和挂断具体解释
1.通过aidl及反射实现挂断电话 详细分三步: (1)ITelephony.aidl ,必须新建com.android.internal.telephony包并放入ITelephony.aidl文件 ...
- Android 实现自动接听和挂断电话功能
添加权限 <uses-permission android:name="android.permission.CALL_PHONE"/> <uses-permis ...
- Android 对电话进行监听和挂断
1.添加权限 <!--拨打电话的权限--><uses-permission android:name="android.permission.PROCESS_OUTGOIN ...
- Android开发之通过反射获取到挂断电话的API
Android开发黑名单工具类,需要用到挂断电话的API,但是该API处于隐藏状态,需要通过反射得到该方法.. 步骤: 1.通过当前类获取到ServiceManager的字节码 Class< ? ...
- android 自己主动拒接后再取消自己主动拒接,该联系人来电界面无图标显示,且点击挂断无反应
1. 设置一个联系人为自己主动拒接 2. 该联系人来电 3. 取消该联系人的自己主动拒接 4. 该联系人来电 Error: 来电界面无头像显示,直接显示黑屏,且点击拒接butt ...
- 内容观察者 ContentObserver 监听短信、通话记录数据库 挂断来电
Activity public class MainActivity extends ListActivity { private TextView tv_info; private ...
- Android7.0 Phone应用源码分析(四) phone挂断流程分析
电话挂断分为本地挂断和远程挂断,下面我们就针对这两种情况各做分析 先来看下本地挂断电话的时序图: 步骤1:点击通话界面的挂断按钮,会调用到CallCardPresenter的endCallClicke ...
- Ubuntu或linux 运行后台进程运行不挂断的办法
nohup python ChatReq.py 20000 >>log_cronjob.txt 2>&1 & 之前把nohup去掉,发现就算运行python Chat ...
随机推荐
- Asp.net 主题 【2】
通常我们经常看到网页,一些软件提供换肤功能,各种主题间切换.ASP.NET 2.0 中可以用Theme和skin以及CSS轻松实现这个功能. 首先简单介绍一下三种技术:主题(Theme)技术,面板(s ...
- 低字节序和高字节序相互转换(Little Endian/Big Endian)
这个例子展示了如何转换整形数字的字节顺序,该方法可以用来在little-endian和big-endian之间转换. 说明:Windos(x86,x64)和Linux(x86,x64)都是little ...
- IDEA14下配置SVN
本来以为是很简单的事情,没想到也浪费我有一会的时间,中间也出现了多多少少的问题. 1.在官网下载SVN,版本要为1.8,切忌不能1.9,否则会出错. 在安装SVN的时候,不能一路下一步,我们要安装命令 ...
- 解决jQuery插件sliderjs, 点击插件分页,导航按钮后不能重新开始.
jQuery SlidesJS - Can't restart animation after clicking on navigation or pagination <!DOCTYPE ht ...
- ActiveReports 交互式报表之向下钻取解决方案
在 ActiveReports 中可以动态的显示或者隐藏某区域的数据,通过该功能用户可以根据需要显示或者隐藏所关心的数据,结合数据排序.过滤等功能可以让用户更方便地分析报表数据. 本文中展示的是销售数 ...
- iPhone 6 图像渲染揭秘(转)
几天前,Apple发布了iPhone 6 Plus. 新的iPhone大幅改变了图像在屏幕上渲染的方式.我们做了一个图表进行详细分析. 分析. 转自:转送
- 理解angularJS中作用域$scope
angularJS中作用域是什么 作用域(scope)是构成angularJS应用的核心基础,在整个框架中都被广泛使用,因此了解它如何工作是非常重要的 应用的作用域是和应用的数据模型相关联的,同时作用 ...
- gulpfile的结构
使用了 yargs 用于获取启动参数,针对不同参数,切换任务执行过程时需要,本项目中的useCache和useSess path 不明,貌似是用来将某个目录中的文件 ...
- memcache锁
锁的使用,一般情况是针对并发或者我们希望程序(crontab的job)串行处理,我们加锁的办法有很多,像文件锁,数据库锁,或者memcache锁,这里关注一下memcache锁,针对memcache锁 ...
- 10个重要的Linux ps命令实战
Linux作为Unix的衍生操作系统,Linux内建有查看当前进程的工具ps.这个工具能在命令行中使用. PS 命令是什么 查看它的man手册可以看到,ps命令能够给出当前系统中进程的快照.它能捕获系 ...