Android 7.0模拟来电

写作目的

有时为了测试的需要,在没SIM卡的机器上测试来电,需要一种一种模拟技术。这篇文章***模拟来电的实现***给出了实现的方式,但说的比较概要。本篇文章则根据自己的实践步骤整理而成,对于具体实现给出了参考。正如原文章所说,Android 5.0版本以前和以后(包括5.0)的实现方式是不同的。本文则是在Android 7.0上实践而来。

代码来源

本文章是在lineageos 14.1的版本上测试的。其源码中已经包括了模拟来电的完整代码,我的工作就是编译其测试用的应用程序即可。 代码路径在:packages/services/Telecomm/testapps。
先把源码编译一遍,再用如下命令单独编译此app: ninja -f out/build-lineage_thea.ninja TelecomTestApps。
编译之后,生成TelecomTestApps.apk, 把它push 到 /system/app/目录中,重启机器,在应用程序列表中就可以看到TestConnectionService, Test Dialer, Test InCall UI三个图标。测试来电要用的就是TestConnectionService。

测试步骤

测试之前,先在设置-应用程序中找到TelecomTestApps, 在权限中打开Phone权限。
然后点击TestConnectionService, 在通知栏中先找到"Test Phone Accounts",  展开此通知,点击“REG. ACCT.” , 先注册一个PhoneAccount, 否则会有权限错误:This PhoneAccountHandle is not registered for this user!
最后展开"Test Connection Service"通知,点击“ADD CALL”, 来电就来了。主要是通知 TelecomManager.from(context).addNewIncomingCall(phoneAccount, extras);
来实现来电的。

后记

关于在Android 4.4上模拟来电,原文中也有介绍,我的理解如下:

  1. 修改frameworks中的frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
    在创建一个GSMPhone对象的时候,创建一个虚拟的BaseCommands:

    if(simulated_phone == 0){
    phone = new PhoneProxy(new GSMPhone(context,
    ci, sPhoneNotifier, false, i), i);
    } else {
    CommandsInterface simulated_ci = new SimulatedCommands();
    Rlog.i(LOG_TAG, "Creating Simulated GSMPhone " + i);
    phone = new PhoneProxy(new GSMPhone(context,
    simulated_ci, sPhoneNotifier, true, i), i);
    }

  2. 写一个测试程序,调用如下接口,触发来电:

    Phone ph = PhoneFactory.getDefaultPhone(link_id);
    SimulatedRadioControl mRadioControl = ph.getSimulatedRadioControl();
    mRadioControl.triggerRing(phoneNumber);

主要代码如上,还未测试,后续更新结果.

====================
更新,有两个问题需要说明:
一、PhoneFactory.getDefaultPhone调用有异常java.lang.RuntimeException: PhoneFactory.getDefaultPhone must be called from Looper thread, 这个问题的原因是创建Phone的进程是com.android.phone,创建的代码在packages/service/telephony/src/com/android/phone/PhoneApp.java:

public void onCreate() {
mPhoneGlobals = new PhoneGlobals(PhoneApp.this);
mPhoneGlobals.onCreate();

}

当调用getDefaultPhone()时对比Looper对象,调用者与Phone有不一样就抛出此异常。所以必须调用者也设置运行在com.android.phone,具体可参考网上的文章PhoneFactory.getDefaultPhone must be called from Looper thread

二、经测试,在Android 4.4上成功模拟来电。但是有一个小问题,在来电界面上,不能显示来电手机号码。
对于此问题,跟踪了一下流程,大致过程如下:

  1. frameworks/opt/telephony/src/java/com/android/internal/telephony/test/SimulatedCommands.java中调用triggerRing()之后的调用到:
    simulatedCallState.triggerRing(number);
  2. 调用到 telephony/src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java中triggerRing()。此方法中生成CallInfo对象。
  3. SimulatedCommands 中public void getCurrentCalls方法被调用得到来电,此方法会调用simulatedCallState.getDriverCalls(), 把CallInfo对象转换成DriverCall对象,传递出去。
  4. ./telephony/src/java/com/android/internal/telephony/gsm/GsmCallTracker.java中的 handlePollCalls(AsyncResult ar)方法中,从DriverCall对象构造Connection对象:

DriverCall dc = null;

dc = (DriverCall) polledCalls.get(curDC);
mConnections[i] = new GsmConnection(mPhone.getContext(), dc, this, i);

  1. 经过一系列调用,走到packages/services/Telephony/src/com/android/phone/CallModeler.java中的private boolean updateCallFromConnection(Call call, Connection connection,
    boolean isForConference)方法,此方法从Connection提取信息来构造Call对象:


// Number presentation
final int newNumberPresentation = connection.getNumberPresentation();
if (call.getNumberPresentation() != newNumberPresentation) {
call.setNumberPresentation(newNumberPresentation);
changed = true;
}

  1. Call对象中设置presentation到CallIdentification对象mIdentification:

public void setNumberPresentation(int presentation) {public void setNumberPresentation(int presentation) {
mIdentification.setNumberPresentation(presentation);
}

  1. 最后apps/InCallUI/src/com/android/incallui/CallCardPresenter.java中显示来电信息,其初始化中会提取出CallIdentification对象, 并搜索联系人中是否保存此号码对应的信息等:

public void init(Context context, Call call) {
final CallIdentification identification = call.getIdentification();

startContactInfoSearch(identification, true,
call.getState() == Call.State.INCOMING);
}

  1. 在apps/InCallUI/src/com/android/incallui/ContactInfoCache.java中把CallIdentification对象转换成CallerInfo对象:

public static ContactCacheEntry buildCacheEntryFromCall(Context context,
CallIdentification identification, boolean isIncoming) {
final ContactCacheEntry entry = new ContactCacheEntry();
// TODO: get rid of caller info.
final CallerInfo info = CallerInfoUtils.buildCallerInfo(context, identification);
ContactInfoCache.populateCacheEntry(context, info, entry,
identification.getNumberPresentation(), isIncoming);
return entry;
}

  1. 上述public static void populateCacheEntry(Context context, CallerInfo info, ContactCacheEntry cce,
    int presentation, boolean isIncoming) 方法中根据CallerInfo来构造联系人查找结果对象ContactCacheEntry, 其中有如下判断, 根据传入的presentation来决定来电界面显示的内容。


    } else if (presentation != Call.PRESENTATION_ALLOWED) {
    // This case should never happen since the network should never send a phone #
    // AND a restricted presentation. However we leave it here in case of weird
    // network behavior
    displayName = getPresentationString(context, presentation);
    Log.d(TAG, " ==> presentation not allowed! displayName = " + displayName);

  2. 问题到这就明了了,来电界面显示号码的地方总是“未知”,是因为上述displayNmae的值"未知", 原因是presentation值设置的不对,这里的值是0。此值的源头是在telephony/src/java/com/android/internal/telephony/test/SimulatedGsmCallState.java中的 DriverCall中设置的。在
    toDriverCall(int index)方法中,进行如下粗体修改,成功显示号码:

DriverCall
toDriverCall(int index) {
DriverCall ret;
ret = new DriverCall();
ret.index = index;
ret.isMT = mIsMT;
ret.numberPresentation = 1;

}

Android 7.0模拟来电相关推荐

  1. android 模拟来电广播,在Android模拟器上模拟来电

    最近项目要做一个控制来电显示的Android 应用 需要在Emulator上模拟来电 效果 方法如下: 1.单个电话 打开命令行cmd,输入telnet 回车. 然后输入 o localhost 55 ...

  2. android 5.0 模拟sd卡,如何使用为Android5.0(Lolliop)提供的新的SD卡访问API?

    在下面链接的我的Android项目中,您可以找到允许在Android 5中的ExtSDCard上编写的工作代码.它假设用户可以访问整个SD卡,然后允许您在这张卡上随时随地写东西.(如果您只想访问单个文 ...

  3. android 8.0模拟点击,安卓8.0能用的模拟器

    小鸡模拟器.有mine模拟器.KE模拟器. 1.Genymotio,适合人群:开发者.测试人员.有一定版配置基础,配合VirtualBox运行,流畅兼容较好,需要一定配置经验,英文界面. 2.逍遥安卓 ...

  4. Android 中 RegistrantList消息处理机制 以android 5.0 MT为例

    这其实是观察者模式的一种实现形式 先明确两个身份 1.RefistrantList 通知者 2.Registrant 观察者,这是一个一对多的关系,在有事件更新时,凡是在名单上登记过的对象,都会收到通 ...

  5. android10.0的来电铃声代码流程

    好的.Android 10.0 的来电铃声流程如下: 电话接收器接收到来电信号时,会触发来电广播. 广播接收器监听来电广播,并收到广播后进行处理. 广播接收器会根据当前的来电铃声设置(包括默认铃声.联 ...

  6. android模拟来电功能,救场神器!假装有人打电话来的虚拟来电软件推荐

    原标题:救场神器!假装有人打电话来的虚拟来电软件推荐 春节期间,相信大家都有不少饭局,有时候想借故先离开,但是又找不到比较合适的理由,这个时候该怎么来化解呢?今天,小编就给大家分享两款救场神器,这是一 ...

  7. Android 7.0来电全屏显示 如何修改

    在Android 7.0来电全屏显示 如何修改呢? 1.alps/frameworks\base\packages\SystemUI\src\com\android\systemui\statusba ...

  8. android 模拟器监听短信,android模拟器用命令和DDMS模拟来电和短信

    以下方法均测试成功 一.用命令模拟 (一).模拟来电 1.打开命令行cmd,输入telnet 回车. 2.然后输入 o localhost 5554 回车,连到Emulator上. 3.输入gsm c ...

  9. android 模拟器监听短信,android模拟器用命令和DDMS模拟来电和短信(示例代码)

    以下方法均测试成功 一.用命令模拟 (一).模拟来电 1.打开命令行cmd,输入telnet 回车. 2.然后输入 o localhost 5554 回车,连到Emulator上. 3.输入gsm c ...

最新文章

  1. 81. Leetcode 21. 合并两个有序链表 (排序)
  2. HANA kernel dump
  3. html5证书,1+X证书Web前端开发HTML专项练习
  4. GC算法-标记清除算法
  5. jar启动报错:org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputExcept
  6. 我的服务端JS文件合并工具
  7. EIGRP MD5认证实例
  8. asp.net c# 常见面试试题总结汇总(含答案)
  9. MD(d)、MT(d)编译选项的区别
  10. IIS添加MIME类型支持 rmvb 等播放
  11. C++ OpenCV实现图像双三次插值算法
  12. 单片机音频信号分析仪
  13. VS.NET(C#)-3.13_Panel控件
  14. 树莓派摄像头远程和本地观看视频
  15. 艾思瑞吡非尼酮在哪报销
  16. 狼性教育——让孩子成为主宰命运地强者
  17. XDMCP远程连接Linux桌面(lightdm) ps -ef |grep lightdm
  18. 关于智能家居、360wifi、wifi开关,以及wifi芯片的选择
  19. Ubuntu系统的有线网卡驱动问题
  20. 基于C51单片机的DA方波可控制发生器

热门文章

  1. 小波阈值去噪的原理及程序
  2. vue 图片显示失败 显示默认图片
  3. 温度补偿 matlab,基于传感器温度补偿方法的双指数函数模型的温度补偿算法设计...
  4. linux 的top命令详解
  5. 爬虫学习笔记(第二章)requests模块
  6. APEX包管理器简述(二)
  7. 2020年最后15天总结
  8. 异地远程连接在家里的群晖NAS【无公网IP,免费内网穿透】
  9. 数据库--视图的基本概念以及作用
  10. ubuntu下,在QT中利用科大讯飞语音库实现语音合成TTS