第一部分:从java端发送at命令的处理流程。

拨出电话流程:

1、Contacts的AndroidManifest.xml 中android:process="android.process.acore" 说明此应用程序运行在acore进程中。

DialtactsActivity的intent-filter的action属性设置为main,catelog属性设置为launcher,所以此 activity能出现在主菜单中,并且是点击此应用程序的第一个界面。dialtactsactivity包含四个tab,分别由 TwelveKeyDialer、RecentCallsListActivity,两个activity-alias DialtactsContactsEntryActivity和DialtactsFavoritesEntryActivity分别表示联系人和收藏 tab,但是正真的联系人列表和收藏是由ContactsListActivity负责。

2、进入TwelveKeyDialer 中OnClick方法,按住的按钮id为:R.id.dialButton,执行placecall()方法:

Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,Uri.fromParts("tel", number, null));

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

startActivity(intent);

3、intert.ACTION_CALL_PRIVILEGED实际字符串为 android.intent.action.CALL_PRIVILEGED,通过查找知道了packegs/phone下面的 AndroidManifest.xml中PrivilegedOutgoingCallBroadcaster activity-alias设置了intent-filter,所以需要找到其targetactivity为 OutgoingCallBroadcaster。所以进入OutgoingCallBroadcaster的onCreate()中:

String action = intent.getAction();
  String number = PhoneNumberUtils.getNumberFromIntent(intent, this);
  if (number != null) {
         number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
         number = PhoneNumberUtils.stripSeparators(number);
   }
  final boolean emergencyNumber =
                (number != null) && PhoneNumberUtils.isEmergencyNumber(number);

获取过来的Action以及Number,并对Action以及Number类型进行判断。

//如果为callNow = true;则启动InCall界面:

intent.setClass(this, InCallScreen.class);

startActivity(intent);

并发送广播给OutgoingCallReceiver:

Intent broadcastIntent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);

if (number != null) broadcastIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

broadcastIntent.putExtra(EXTRA_ALREADY_CALLED, callNow);

broadcastIntent.putExtra(EXTRA_ORIGINAL_URI, intent.getData().toString() );

sendOrderedBroadcast(broadcastIntent, PERMISSION,
                new OutgoingCallReceiver(), null, Activity.RESULT_OK, number, null);

4、Intent.ACTION_NEW_OUTGOING_CALL实际字符串 android.intent.action.NEW_OUTGOING_CALL,通过查找知道了packegs/phone下面的 androidmanifest.xml中OutgoingCallReceiver Receiver接收此intent消息。找到OutgoingCallBroadcaster类中的内部类OutgoingCallReceiver, 执行onReceive()函数:

执行doReceive(context, intent);方法:

获取传给来的号码,根据PhoneApp的实例获取PhoneType等。最后启动InCall界面:

Intent newIntent = new Intent(Intent.ACTION_CALL, uri);

newIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number);

newIntent.setClass(context, InCallScreen.class);

newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

5、请求拨号的java部分流程

6、请求拨号的c/c++部分流程

6.1、初始化事件循环,启动串口监听,注册socket监听。

rild.c->main()

(1)、RIL_startEventLoop

//建立事件循环线程

ret = pthread_create(&s_tid_dispatch, &attr, eventLoop, NULL);

//注册进程唤醒事件回调

ril_event_set (&s_wakeupfd_event, s_fdWakeupRead, true,

processWakeupCallback, NULL);

rilEventAddWakeup (&s_wakeupfd_event);

//建立事件循环

ril_event_loop

for (;;) {

...

n = select(nfds, &rfds, NULL, NULL, ptv);

// Check for timeouts

processTimeouts();

// Check for read-ready

processReadReadies(&rfds, n);

// Fire away

firePending();

}

(2)、funcs = rilInit(&s_rilEnv, argc, rilArgv);//实际是通过动态加载动态库的方式执行reference-ril.c中的RIL_Init

//单独启动一个线程读取串口数据

ret = pthread_create(&s_tid_mainloop, &attr, mainLoop, NULL);

fd = open (s_device_path, O_RDWR);

ret = at_open(fd, onUnsolicited);

ret = pthread_create(&s_tid_reader, &attr, readerLoop, &attr);

RIL_requestTimedCallback(initializeCallback, NULL, &TIMEVAL_0);

在initializeCallback中执行的程序:

setRadioState (RADIO_STATE_OFF);

at_handshake();

/* note: we don't check errors here. Everything important will

be handled in onATTimeout and onATReaderClosed */

/* atchannel is tolerant of echo but it must */

/* have verbose result codes */

at_send_command("ATE0Q0V1", NULL);

/* No auto-answer */

at_send_command("ATS0=0", NULL);

...

//注册rild socket端口事件监听到事件循环中

(3)、RIL_register(funcs);

s_fdListen = android_get_control_socket(SOCKET_NAME_RIL);

ret = listen(s_fdListen, 4);

ril_event_set (&s_listen_event, s_fdListen, false,

listenCallback, NULL);//将此端口加入事件select队列

rilEventAddWakeup (&s_listen_event);

如果rild socket端口有数据来了将执行listencallback函数

listencallback

//为此客户端连接创建新的监听句柄,s_fdListen继续监听其他客户端的连接。

s_fdCommand = accept(s_fdListen, (sockaddr *) &peeraddr, &socklen);

ril_event_set (&s_commands_event, s_fdCommand, 1,

processCommandsCallback, p_rs);//将此端口加入事件select队列

rilEventAddWakeup (&s_commands_event);

6.2、socket监听,收到dial的socket请求

processCommandsCallback

//读数据到p_record中

ret = record_stream_get_next(p_rs, &p_record, &recordlen);

processCommandBuffer(p_record, recordlen);

p.setData((uint8_t *) buffer, buflen);

// status checked at end

status = p.readInt32(&request);

status = p.readInt32 (&token);//请求队列中的序号

pRI = (RequestInfo *)calloc(1, sizeof(RequestInfo));

pRI->token = token;

/*

包含#include "ril_commands.h"语句,结构体如下:

typedef struct {

int requestNumber;

void (*dispatchFunction) (Parcel &p, struct RequestInfo *pRI);

int(*responseFunction) (Parcel &p, void *response, size_t responselen);

} CommandInfo;

*/

pRI->pCI = &(s_commands[request]);

pRI->p_next = s_pendingRequests;

s_pendingRequests = pRI;

pRI->pCI->dispatchFunction(p, pRI);

//假设是接收了dial指令,pRI->PCI->dispatchFunction(p,pRI),调用dispatchDial (p,pRI)

dispatchDial (p,pRI)

s_callbacks.onRequest(pRI->pCI->requestNumber, &dial, sizeof(dial), pRI);

in reference-ril.c onRequest()

...

switch (request) {

case RIL_REQUEST_DIAL:

requestDial(data, datalen, t);

asprintf(&cmd, "ATD%s%s;", p_dial->address, clir);

ret = at_send_command(cmd, NULL);

err = at_send_command_full (command, NO_RESULT, NULL, NULL, 0, pp_outResponse);

err = at_send_command_full_nolock(command, type, responsePrefix, smspdu,timeoutMsec,   sponse);

err = writeline (command);

//此处等待,直到收到成功应答或失败的应答,如:ok,connect,error cme等

err = pthread_cond_wait(&s_commandcond, &s_commandmutex);

waiting....

waiting....

/* success or failure is ignored by the upper layer here.

it will call GET_CURRENT_CALLS and determine success that way */

RIL_onRequestComplete(t, RIL_E_SUCCESS, NULL, 0);

p.writeInt32 (RESPONSE_SOLICITED);

p.writeInt32 (pRI->token);

errorOffset = p.dataPosition();

p.writeInt32 (e);

if (e == RIL_E_SUCCESS) {

/* process response on success */

ret = pRI->pCI->responseFunction(p, response, responselen);

if (ret != 0) {

p.setDataPosition(errorOffset);

p.writeInt32 (ret);

}

}

sendResponse(p);

sendResponseRaw(p.data(), p.dataSize());

blockingWrite(fd, (void *)&header, sizeof(header));

blockingWrite(fd, data, dataSize);

6.4、串口监听收到atd命令的应答"OK"或"no carrier"等

readerLoop()

line = readline();

processLine(line);

handleFinalResponse(line);

pthread_cond_signal(&s_commandcond);//至此,前面的等待结束,接着执行RIL_onRequestComplete函数

6.5、java层收到应答后的处理,以dial为例子.

ril.java->RILReceiver.run()

for(;;)

{

...

length = readRilMessage(is, buffer);

p = Parcel.obtain();

p.unmarshall(buffer, 0, length);

p.setDataPosition(0);

processResponse(p);

type = p.readInt();

if (type == RESPONSE_SOLICITED) {

processSolicited (p);

serial = p.readInt();

rr = findAndRemoveRequestFromList(serial);

rr.mResult.sendToTarget();

......

}

CallTracker.java->handleMessage (Message msg)

switch (msg.what) {

case EVENT_OPERATION_COMPLETE:

ar = (AsyncResult)msg.obj;

operationComplete();

cm.getCurrentCalls(lastRelevantPoll);

第二部分:unsolicited 消息从modem上报到java的流程。

C++部分:

readerLoop()

line = readline();

processLine(line);

handleUnsolicited(line);

if (s_unsolHandler != NULL) {

s_unsolHandler (line1, line2);//实际执行的是void onUnsolicited (const char *s, const char *sms_pdu)

if (strStartsWith(s,"+CRING:")|| strStartsWith(s,"RING")

|| strStartsWith(s,"NO CARRIER") || strStartsWith(s,"+CCWA") )

RIL_onUnsolicitedResponse (RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);

p.writeInt32 (RESPONSE_UNSOLICITED);

p.writeInt32 (unsolResponse);

ret = s_unsolResponses[unsolResponseIndex].responseFunction(p, data, datalen);

ret = sendResponse(p);

sendResponseRaw(p.data(), p.dataSize());

ret = blockingWrite(fd, (void *)&header, sizeof(header));

blockingWrite(fd, data, dataSize);

Java部分:

ril.java->RILReceiver.run()

for(;;)

{

...

length = readRilMessage(is, buffer);

p = Parcel.obtain();

p.unmarshall(buffer, 0, length);

p.setDataPosition(0);

processResponse(p);

processUnsolicited (p);

response = p.readInt();

switch(response) {

...

case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break;

...

}

switch(response) {

case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:

if (RILJ_LOGD) unsljLog(response);

mCallStateRegistrants

.notifyRegistrants(new AsyncResult(null, null, null));

...

}

第三部分:猫相关的各种状态的监听和通知机制

第四部分:通话相关的图标变换的工作原理。

A. 注册监听部分

B.事件通知部分

Android Dial处理过程相关推荐

  1. Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(下)

       本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning 上篇文章<<Android中measure过程.WRAP_CONTENT详解以及xml布局文 ...

  2. android Android项目构建过程

    今天,简单讲讲android studio如何把写好的工程打包成apk的. 平时开发过程中我们通过android studio编写完成android项目之后直接点击 Run 'app'就可以在buil ...

  3. android view绘制过程

    应用程序窗口内部所包含的视图对象的实际类型为DecorView.DecorView类继承了View类,是作为容器(ViewGroup)来使用的,它的实现如图1所示: 每一个应用程序窗口的视图对象都有一 ...

  4. Android的启动过程

    Passion注:本篇文章描述的是Android的启动过程,不包括Linux的启动过程 分别来自 http://dingpwen.spaces.live.com/blog/cns!4CADD02D22 ...

  5. Android studio安装过程中入的坑的记录与记录

    Android studio安装过程中入的坑的记录与记录 * 由于最近项目的需求,所以最近一直在配置安卓的开发环境,之前用的是Eclipse + ADT的模式开发的,配置环境也花了一些时间,但是由于谷 ...

  6. Android 系统(216)---Android坐标分析过程

    Android坐标分析过程 Android中有两种坐标系,分别是Android坐标系和视图坐标系.  首先看一下屏幕区域划分  //获取状态栏高度 Rect rect= new Rect(); get ...

  7. Framework学习(二)Android的启动过程

    Android设备的启动过程 上一张介绍了Android的系统的整体架构,认识了体系的构造,今天就讲一下,Android的系统的启动过程. 看了架构图,我们知道架构的设计是至上而下的,但是,Andro ...

  8. 解决Android Studio安装过程中“SDK tools directory is missing”的问题

    解决Android Studio安装过程中"SDK tools directory is missing"的问题 参考文章: (1)解决Android Studio安装过程中&qu ...

  9. android 按键用户点击事件,Android按键事件处理过程详解

    Android按键事件处理过程详解 (2013-09-26 14:05:19) 标签: it 在Android系统中,存在多种界面事件,如点击事件.触摸事件.焦点事件和菜单事件等,在这些界面事件发生时 ...

最新文章

  1. pwn入门-PLT表与GOT表、libc入门
  2. TLS--线程局部存储
  3. Dotnet洋葱架构实践
  4. 《SAS编程与数据挖掘商业案例》学习笔记之十九
  5. angular依赖注入_Angular依赖注入简介
  6. servlet下根据相对路径找资源
  7. dsp呼吸灯C语言编程,DSP28335 呼吸灯程序
  8. 牛顿(Newton)插值及其MATLAB程序
  9. html5离线缓存使用
  10. unity打开摄像头
  11. 【Web理论篇】Web应用程序安全与风险
  12. 传说中的世界500强面试题-数学能力(2)
  13. ps随机排列_[PS]圆点随机不重叠排列脚本
  14. 网页播放rtsp视频流最终方案
  15. 聊天室应用开发实践(二):实现基于 Web 的聊天室
  16. AM中使用PML语言标注船体结构
  17. 格式为[区号-座机号-分机号]的座机号校验正则
  18. Mina中的Snark Worker
  19. 台式电脑win10系统怎么开启无线服务器,台式电脑win10怎么连wifi_window10台式如何连接wifi...
  20. vue html模板递归,vue使用递归组件实现多级列表

热门文章

  1. 谈判技巧之奇怪的压力
  2. abp vnext安装模块
  3. 前端开发过程中,经常遇到复制粘贴后自动空白一行,该如何解决这个问题哪?
  4. Mac 解决github 下载慢问题
  5. java中instr函数,Oracle中instr函数使用方法
  6. List中addAll()方法简介
  7. Mysql无法启动报错19884 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
  8. Surfacebook误删显卡恢复办法/无法打开nVidia控制面板解决办法/找不到显卡恢复方法
  9. IT业务运维可观测技术的发展浅析
  10. Vue 父组件如何触发子组件中的方法