start and end call use itelephony and how to pick up a call
Bluetooth Headset service:
但想想而已。 没有蓝牙耳机如何调用它来接听电话。想想有点搞笑。
网上扒的通过添加一个ITelephony.aidl来反射,注意aidl的写法,如果使用studio 来写,最好是利用菜单生成aidl或者抄写下它是如何生成的。
这里解释了一下原理;
使用java 反射来获取安卓内部的私有方法
TelephonyManager 类是由远程服务来实现的,它实质是
调用远程电话服务,这个工作具体是由AIDL来做的,remote procedure call (RPC)
这样远程服务使用公有TelephonyManager 就可以不暴露实现,你需要做的就是利用 getITelephony() 来得到远程程序调用的客户端,此方法返回一个ITelephony类型的对象。
有了这个对象,就可以得到其类对象和内部方法endCall() ,这样我们就能调用这个方法。
现在这个endCall() 是运行在远程程序调用的客户端,它可以发送消息给 远程电话服务(运行在远程服务中),要求终止当前通话。
由于源代码 ITelephony.aidl 是公开的,你可以将代码放在你的工程中,IDE会自动生成ITelephony.java(自动包含了RPC的客户端)
当你在安卓设备上运行时,会调用安卓框架里的ITelephony 对象,并将其转换成 com.android.internal.telephony.ITelephony
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
附上实现:
AndroidManifest.xml
...
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="ANDROID.PERMISSION.MODIFY_PHONE_STATE"/>
...
FragmentCallPhone.java
package org.nd.ui; import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast; import org.nd.R; import java.lang.reflect.Method; import org.nd.common.Common; /**
* Created by HAO on 2015/7/17.
*/
public class FragmentCallPhone extends Fragment implements View.OnClickListener { public FragmentCallPhone() {
} private Button btnCall, btnEnd;
private TextView edit_phone;
private static final int AUTO_END_CALL_AFTER_ONE_MINUTE = 10000;
private Handler mHandler;
private Handler cutHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Common.HEART_BEAT:
Log.d("org.nd", "HEART_BEAT_TWO");
break;
case Common.REFLECTION_ERROR:
Log.d("org.nd", "HEART_BEAT_THREE");
break;
case Common.HEART_BEAT_TWO:
Log.d("org.nd", "HEART_BEAT_ONE ");
break;
}
}
};
private boolean call_once = true; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_layout_call, container, false);
btnCall = (Button) view.findViewById(R.id.call_phone);
btnCall.setOnClickListener(this);
btnEnd = (Button) view.findViewById(R.id.dial_and_call);
btnEnd.setOnClickListener(this);
edit_phone = (TextView) view.findViewById(R.id.edit_phone); MyPhoneListener phoneListener = new MyPhoneListener();
TelephonyManager telephonyManager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
mHandler = new Handler();
return view;
} @Override
public void onResume() {
super.onResume();
// btnCall.callOnClick();
} @Override
public void onClick(View v) {
String uri, number = edit_phone.getText().toString();
switch (v.getId()) {
case R.id.call_phone:
if (number.isEmpty())
number = "10000";
// if(!autoEnd.isChecked())
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
call_once = false;
TelephonyManager telephonyManager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE); Message msg = new Message();
try {
Class c = Class.forName(telephonyManager.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
Object telephonyService = m.invoke(telephonyManager); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
msg.what = Common.HEART_BEAT;
cutHandler.sendMessage(msg);
} catch (Exception e) {
msg = new Message();
msg.what = Common.REFLECTION_ERROR;
cutHandler.sendMessage(msg);
Log.d("org.nd", e.toString());
}
}
}, AUTO_END_CALL_AFTER_ONE_MINUTE); uri = "tel:" + number;
Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse(uri));
startActivity(callIntent);
Message msg = new Message();
msg.what = Common.HEART_BEAT_TWO;
cutHandler.sendMessage(msg);
break;
case R.id.dial_and_call:
uri = "tel:" + edit_phone.getText().toString();
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse(uri));
startActivity(dialIntent);
break; }
} private class MyPhoneListener extends PhoneStateListener {
private boolean onCall = false; @Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// phone ringing...
Toast.makeText(getActivity(), incomingNumber + " calls you",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// one call exists that is dialing, active, or on hold
Toast.makeText(getActivity(), "on call...",
Toast.LENGTH_LONG).show();
//because user answers the incoming call
onCall = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
// in initialization of the class and at the end of phone call
// detect flag from CALL_STATE_OFFHOOK
if (onCall == true) {
Toast.makeText(getActivity(), "restart app after call",
Toast.LENGTH_LONG).show();
// restart our application
Intent restart = getActivity().getBaseContext().getPackageManager().
getLaunchIntentForPackage(getActivity().getBaseContext().getPackageName());
restart.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(restart);
onCall = false;
}
break;
default:
break;
}
}
}
}
由于接电话需要改变电话的状态,而谷歌对于这一行为后来都加了保护,不允许开发者修改。所以引发了无数开发者的研究热情。
源头是这样的:
public static final String MODIFY_PHONE_STATE Added in API level 1
Allows modification of the telephony state - power on, mmi, etc. Does not include placing calls. Not for use by third-party applications. Constant Value: "android.permission.MODIFY_PHONE_STATE"
方法一: answerRingingCall
这是按照挂电话的代码写的。不通过;
TelephonyManager telephonyManager = (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
try {
Class c = Class.forName(telephonyManager.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
Object telephonyService = m.invoke(telephonyManager); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("answerRingingCall"); // Get the method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke
Log.d(FRAGMENT_TAG, "success?");
} catch (Exception e) {
Log.d(FRAGMENT_TAG, getErrorInfoFromException(e));
}
java.lang.SecurityException: Neither user nor current process has android.permission.MODIFY_PHONE_STATE.
方法二:见这里。
适用于Android2.3及2.3以上的版本上 ,但测试发现4.1系统上不管用。
// 报错: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.
但是方法二可以改进:
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);
getActivity().sendOrderedBroadcast(meidaButtonIntent, null);
}
然后就好了,现在我需要验证一下unroot手机是否通过。
过了几天发现,在5.0(Lollipo )平台上又是无作为的。敢情真是逃不掉Root
start and end call use itelephony and how to pick up a call的更多相关文章
- ITelephony.aidl
在src下先建立包名为com.android.internal.telephony(右键src > new > package,create package-info.java打钩),然后 ...
- Android来电监听和去电监听
我觉得写文章就得写得有用一些的,必须要有自己的思想,关于来电去电监听将按照下面三个问题展开 1.监听来电去电有什么用? 2.怎么监听,来电去电监听方式一样吗? 3.实战,有什么需要特别注意地方? 监听 ...
- Android 双卡双待识别
简介 Android双卡双待已经越来越普及了,解决双卡双待管理是广大手机开发人员必须得面对的问题,为实现Android平台的双卡双待操作,笔者研究了Android 应用层操作双卡双待的机制. 机制 获 ...
- Android6.0中的权限
Android6.0相比之前的Android版本有一个很大的不同点,就是动态的获取权限.之前我们需要什么权限只需要在Manifest文件中声明即可,在6.0中,又新增了运行时权限的动态检测. Andr ...
- 实现android手机来电拦截系统页面弹出自定义页面特效
如何实现android手机来电拦截系统页面弹出自定义页面特效, 首先: 我们需要注册一个监听来电的广播PhoneStateReceiver 类:其次: 在onReceive里面我们获取an ...
- [Android] adb shell dumpsys的使用
reference to :http://blog.csdn.net/g19920917/article/details/38032413 有两种方法可以查看service list: 1. adb ...
- Class.forName()的作用与使用总结
1.Class类简介: Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识.这项信息纪录了每个对象所属的类.虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类 ...
- Android 对电话进行监听和挂断
1.添加权限 <!--拨打电话的权限--><uses-permission android:name="android.permission.PROCESS_OUTGOIN ...
- Android Framework层Power键关机流程(一,Power长按键操作处理)
一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManag ...
随机推荐
- [.NET] GC垃圾回收机制
前言: 在.NET程序开发中,为了将开发人员从繁琐的内存管理中解脱出来,将更多的精力花费在业务逻辑上,CLR提供了自动执行垃圾回收的机制来进行内存管理.开发人员甚至感觉不到这一过程的存在.CLR执行垃 ...
- 关于InvokeMethod Activity的异步调用
讨论地址:http://www.cnblogs.com/foundation/archive/2009/12/17/1626617.html 结论是IsCompleted的设置被忽略,看代码里注释 u ...
- ssh 无密码登录要使用公钥与私钥
ssh 无密码登录要使用公钥与私钥.linux下可以用用ssh-keygen生成公钥/私钥对,下面我以CentOS为例. 有机器A(192.168.1.155),B(192.168.1.181).现想 ...
- Oracle学习笔记(十)
光标(游标)概念引入 就是一个结果集(查询或者其他操作返回的结果是多个时使用)定义一个光标 cursor c1 is select ename from emp: 从光标中取值 打开光标: --ope ...
- 优秀前端工程师必备: 我要一个新窗口: js开新窗的2种姿势
1.<a href="https://www.cnblogs.com/" title="博客园">当前页面打开博客园</a> js代码等 ...
- Swift:超炫的View Controller切换动画
匿名社交应用Secret的开发者开发了一款叫做Ping的应用,用户可以他们感兴趣的话题的推送. Ping有一个很炫的东西,就是主界面和之间切换的动画做的非常的好.每次看到一个非常炫的动画,都不由得会想 ...
- Python WebDriver 文件上传(一)
昨天写了Web 文件下载的ui自动化,下载之后,今天就要写web 文件上传的功能了. 当然从折腾了俩小时才上传成功.下面写一下自己操作的步骤 首先网上说的有很多方法 如 input 标签的最好做了,直 ...
- Android-自定义圆环
效果图: 布局的代码,指定引用自定义View类: <!-- 绘制圆环 --> <LinearLayout xmlns:android="http://schemas.and ...
- mysql导入数据load data infile用法(转)
们常常导入数据!mysql有一个高效导入方法,那就是load data infile 下面来看案例说明 基本语法: load data [low_priority] [local] infile ' ...
- [转载]MVC、MVP以及Model2(上)
对于大部分面向最终用户的应用来说,它们都需要具有一个可视化的UI与用户进行交互,我们将这个UI称为视图(View).在早期,我们倾向于将所有与视图相关的逻辑糅合在一起,这些逻辑包括数据的呈现.用户操作 ...