参考: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. Rechability的简单使用

    AppDelegate.m #import "AppDelegate.h" #import "Reachability.h" @interface AppDel ...

  2. 泛型,迭代器,LinkedList<E>

    1 <e>里面只能填类,不能用基本数据类型,不过integer 这样的的也行 2在模板类(泛型类中)class demo<e>由于不知道e是那个,所有通常都是重写大家都有的to ...

  3. JavaScript 目标装配式编程(Target Assemble Programming)

    TAP概述 脚本中一切皆对象,若还以传统模式思考编程模式,那简直是对不起脚本解释器的强大支持:我们应该以最接近人类操作方式的来表达人的意图. 更接近工作实践的方式,比如游戏中,一个人物一个角色,人物的 ...

  4. C++封装常用对象和对头文件探索

    在C++实际开发中,难免会使用到一些你极为常用的算法(比如笔者经常使用的多线程技术),实现这些算法的类或是全局函数或是命名空间等等经常都要被使用多次,你会有哪些办法来使用呢?笔者有4个办法. 第一个方 ...

  5. Android学习----Android Studio 技巧汇总

    关于快捷键 The File Structure Popup ctrl+f12此快捷键可以调出当前文件的大纲,并通过模糊匹配快速跳转至指定的方法.勾选上“show anonymous classes” ...

  6. android布局1

    第二类:属性值必须为id的引用名“@id/id-name” 仅RelativeLayout中有效    android:layout_below      在某元素的下方     android:la ...

  7. javascript禁止输入数字

    function onkeypressIsNumber(){ var mainForm = document.mainForm;//mainForm是form表单的ID for(var i=0; i& ...

  8. 省队集训day6 A

    code: #include<cstdio> #include<iostream> #include<cmath> #include<cstring> ...

  9. TCP回射客户程序:main函数

    创建套接字,装填网际网套接字地址结构 创建一个TCP套接字,用服务器的IP地址和端口号装填一个网际网套接字地址结构 我们可从命令行参数取得服务器的IP地址 从头文件unp.h取得服务器的众所周知端口号 ...

  10. 委托的lambda表达式

    委托可以用 Lambda 表达式的方法来表示,很多C#的代码都会大量使用 Lambda 表达式,正确理解它的用法还是很重要的. 基础规则: Lambda 运算符 “=>” 左边表示委托实例所需要 ...