项目要实现的功能:1 按下设备上的按钮后自动拨号 2 拨号中、通话中显示自定义界面
1 按下按钮自动拨号?当时就懵逼了,我怎么监听硬件上的点击事件,网上一查,GPIO是什么鬼,没办法网上各种翻找,什么设置输出、输入、高电平、低电平、IO口、索引值,慢慢弄明白了一些,可问题是不同的厂商提供的板子索引值什么的不同啊,没办法,只能应用里面switch case 一个一个适配了
2 去电监听,刚开始也是各种查找,各种失败,只能一步一步来了,当然前提是打系统签名包:步骤如下
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package=""
android:sharedUserId="android.uid.system"> //添加系统权限
下载signapk.jar ,platform.pk8,platform.x509.pem这3个文件放在同目录下
java -jar signapk.jar platform.x509.pem platform.pk8 old.apk new.apk
cmd cd到目录下 执行java -jar signapk.jar platform.x509.pem platform.pk8 old.apk new.apk
platform.pk8,platform.x509.pem这两个文件我用的是设备厂商提供的,不是Android原生的,不同版本,不同厂商可能会不同,这个需要问下各自厂商,当然了,如果你们公司牛掰,你可以自己定制这两个文件,让设备厂商统一使用你们的
继续:
首先开机自启动
public class BootBroadCast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null)
return;
LogUtil.e(intent.getAction());
//开机监听 自启动Service
if (TextUtils.equals(intent.getAction(), Constant.ACTION_BOOT)) {
Intent it = new Intent(context, PhoneService.class);
context.startService(it);
}
//关机监听 停止录像
if (TextUtils.equals(intent.getAction(),Constant.ACTION_SHUTDOWN)){
EventBus.getDefault().post(new Msg(Constant.STOP_RECORD));
}
}
}
去源码里下载相应的AIDL文件,结构如下,包名必须是这样的不能更改
监听到GPIO事件后开始拨号
try {
LogUtil.e("自动拨号");
Class<TelephonyManager> managerClass = TelephonyManager.class;//得到TelephonyManager的Class对象
Method getITelephony = managerClass.getDeclaredMethod("getITelephony", (Class[]) null);
//打开权限
getITelephony.setAccessible(true);
//得到TelephonyManager对象
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
//得到ITelephony对象,进行所需要的操作
ITelephony iTelephony = (ITelephony) getITelephony.invoke(manager, (Object[]) null);
//打电话
iTelephony.call(context.getPackageName(), "被拨打的号码");
// Thread.sleep(1500);
// context.startActivity(new Intent(context, MainActivity.class));
} catch (Exception e) {
e.printStackTrace();
}
定义广播监听电话状态
public class PhoneCallReciver extends BroadcastReceiver {
private static final String ACTION_CALL_PHONE = "android.intent.action.NEW_OUTGOING_CALL";
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null)
return;
if (TextUtils.equals(Constant.ACTION_CALL_PHONE, intent.getAction())) {
LogUtil.e(intent.getAction());
// Intent it=new Intent(context,MainActivity.class);
// it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// context.startActivity(it);
EventBus.getDefault().post(new Msg(Constant.DIALING));//进入拨号页面
//实时抓取log
AppUtil.getInCallLog("logcat -s Telecom");
}
// if (TextUtils.equals(Constant.ACTION_STATE, intent.getAction())) {
// TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
// LogUtil.e(manager.getCallState());
// switch (manager.getCallState()) {
//来电
// case TelephonyManager.CALL_STATE_RINGING:
// break;
//来电通话中
// case TelephonyManager.CALL_STATE_OFFHOOK:
// break;
//本来想在这里监听挂断状态的,结果不行
// case TelephonyManager.CALL_STATE_IDLE:
// PhoneService.current_click = 0;
// EventBus.getDefault().post(new Msg(Constant.END_CALL));
// break;
// }
// }
}
}
public static void getInCallLog(final String cmd) {
//抓取log日志 过滤刷选出Telecom字段
new Thread(new Runnable() {
@Override
public void run() {
Process pro = null;
BufferedReader bufferedReader = null;
try {
// String[] running = new String[]{"logcat", "|find", "NEW_OUTGOING_CALL"};
pro = Runtime.getRuntime().exec(cmd);
bufferedReader = new BufferedReader(new InputStreamReader(
pro.getInputStream()));
//筛选需要的字串
// String strFilter = " CallList - onUpdate - [Call_";
// String active = "ACTIVE, [Capabilities: CAPABILITY_HOLD CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO]";
// String strFilter = "CallsManager:setCallState:";
String dialing = "CallsManager: setCallState DIALING -> DIALING";
String dialing_active = "CallsManager: setCallState DIALING -> ACTIVE";
String active_disconnect = "CallsManager: setCallState ACTIVE -> DISCONNECTED";
String dialing_disconnect = "CallsManager: setCallState DIALING -> DISCONNECTED";
String removed = "InCallController: onCallRemoved";
String line = null;
while ((line = bufferedReader.readLine()) != null) {
// if (line.contains(dialing)) {//拨号中
// EventBus.getDefault().post(new Msg(Constant.DIALING));
// }
if (line.contains(dialing_active)) {//通话中
LogUtil.e(line);
EventBus.getDefault().post(new Msg(Constant.CALLING));
// getInCallLog("logcat -c");
// break;
}
// if (line.contains(active_disconnect) || line.contains(dialing_disconnect)) {//通话结束
// EventBus.getDefault().post(new Msg(Constant.END_CALL));
// break;
// }
if (line.contains(removed)) {//通话结束
LogUtil.e(line);
EventBus.getDefault().post(new Msg(Constant.END_CALL));
// clearLog("logcat -c");
break;
}
}
pro.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (pro != null) {
pro.destroy();
pro = null;
}
if (bufferedReader != null) {
bufferedReader.close();
bufferedReader = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
清除日志缓存
public static void clearLog() {
Process pro = null;
try {
pro = Runtime.getRuntime().exec("logcat -b all -c");
pro.waitFor();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pro != null) {
pro.destroy();
pro = null;
}
}
}
然而还是存在问题,显示自定义正在拨号界面后会弹出系统拨号界面,刚开始想到的是监听到正在拨号后,延时显示自定义界面,后面想有没有办法禁用系统电话app,解决如下
public static void forbidSysApp(Context context, String pkgName) {
//将APP或组件设置为manifest定义的状态。
// COMPONENT_ENABLED_STATE_DEFAULT,
//启用APP或组件,忽略manifest的定义。
// COMPONENT_ENABLED_STATE_ENABLED,
//禁用APP或组件,忽略manifest的定义。
// COMPONENT_ENABLED_STATE_DISABLED,
//以用户身份禁用APP,忽略manifest的定义。不能用于组件操作。
// COMPONENT_ENABLED_STATE_DISABLED_USER,
//禁用APP直到用户想用才出现。也就是说,正常情况下,用户看不到(比如在Launcher上);但是特殊情况下,用户还是能看到并选择到(比如输入法APP)。不能用于组件操作。
// COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
PackageManager pm = context.getPackageManager();
//禁止系统电话应用运行
pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0);
//启用系统电话应用
//pm.setApplicationEnabledSetting(pkgName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, 0);
}
好,打系统签名包,adb push 进 /system/app ,再adb reboot
测试正常,可是连续多测几次后界面出现错乱,发现LogUtil.e(line)输出的还是上一次的通话信息,然后不断logcat -b all -c , logcat -s Telecom发现日志缓存存在2分钟左右才清空,每次挂断后,等2分钟左右再测试都是正常的,找不到原因为什么日志缓存没有实时清除