标签:
本文与另外一篇分析RIL底层模块的文章是姐妹篇: 基于Android6.0的RIL底层模块分析
根据手机网络制式的不同,通常系统中会扩展Phone.java这个类,扩展成GSMPhone和CDMAPhone。这个类主要是抽象整个手机来处理通信过程中与其他模块的交互。我们以GSMPhone为例,分析来电流程如何从底层传递到上层。该分析主要基于代码,所以会比较啰嗦。
以GSMPhone为例,在PhoneFactory类中有实例化该类的方法:
public static Phone getGsmPhone(int phoneId) {
Phone phone = TelephonyPluginDelegate.getInstance().makeGSMPhone(sContext,sCommandsInterfaces[phoneId], sPhoneNotifier, phoneId);
return phone;
}
这个phone的mCi其实使用sCommandInterfaces第phoneId个元素进行初始化。这个数组是为了支持多卡而设置。
sCommandInterfaces的初始化是:
sCommandsInterfaces = new RIL[numPhones];
所以可以知道其实mCi的真实类型就是RIL类。
GSMPhone会构造一个GsmCallTracker,而在GsmCallTracker中就会在构造函数中调用:
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
其实就是用GsmCallTracker来监听mCi上的电话状态改变EVENT_CALL_STATE_CHANGE啊。注意这个mCi是CommandInterfaces类型(当然实际是RIL类型,这样大家知道在哪里去找实现函数了)。我们理解模块流程,最好从更高层的抽象角度去考虑,深入到细节是你了解运行机制之后才进行的,否则容易迷失在细节中。通过查找RIL相关联的类(比如它继承的类和实现的接口),在BaseCommands里面找到实现函数:
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
mCallStateRegistrants.add(r);
}
看看它搞啥了。将传入的GsmCallTracker实例,响应的事件EVENT_CALL_STATE_CHANGE,以及传入的obj(null)包装成了一个Registrant,并且加入列表mCallStateRegistrants中了。注意传入的参数:
handler:实际传入的是GsmCallTracker类型,这个类也是handler的子类
what:EVENT_CALL_STATE_CHANGE,需要监听的事件类型
在稍微看看Registrant代码,发现就是包装了一下三个传入参数,并且在需要的时候触发事件的发送。mCallStateRegistrants是protected类型,所以可以在其子类RIL里面访问。在processUnsolicited&RIL.java里面确实针对这个做了处理:
//RIL.java
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
break;
//RegistrantList.java
private synchronized void internalNotifyRegistrants (Object result, Throwable exception)
{
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}
}
是监听到了“RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED”事件,才进行了处理。至于这个事件的发出,涉及到了native层的rild,所以暂不在此提及。
其实就是把这个new AsyncResult(null, null, null)发送到mCallStateRegistrants中每个Registrant中去,并且用实例化Registrant时的handler来处理该AsyncResult。也就是返回到了GsmCallTracker中,注意返回信息的msg.what就是实例化该Registrant时候的what参数,针对来电就是EVENT_CALL_STATE_CHANGE。这个会触发:
//handleMessage&GsmCallTracker.java
case EVENT_CALL_STATE_CHANGE:
pollCallsWhenSafe();
break;
//CallTracker.java
protected void pollCallsWhenSafe() {
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
也就是将一个mLastRelevantPoll.what = EVENT_POLL_CALL_RESULT的message传入getCurrentCalls函数。
//RIL.java
public void getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
send(rr);
}
下面来看看RILRequest这个类,非常有意思,它是一个链表实现,应该是作为一个pool的作用。也就是所有的request是放在一个池子里面进行管理(也就是链表,池子比较形象)。需要的时候就obtain一个。
static RILRequest obtain(int request, Message result) {
RILRequest rr = null;
synchronized(sPoolSync) {
if (sPool != null) {
rr = sPool;
sPool = rr.mNext;
rr.mNext = null;
sPoolSize--;
}
}
if (rr == null) {
rr = new RILRequest();
}
rr.mSerial = sNextSerial.getAndIncrement();//依次递增,request的id。类似数据库里面的默认第一个键值_id
rr.mRequest = request;//请求内容,就是RIL_REQUEST_GET_CURRENT_CALLS
rr.mResult = result;
rr.mParcel = Parcel.obtain();//一个序列化的数据,如下所见,保存request内容和request在池中的id
if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
}
// first elements in any RIL Parcel
rr.mParcel.writeInt(request);
rr.mParcel.writeInt(rr.mSerial);
return rr;
}
所以通过注释,看起来RILRequest就是容纳用户请求的一个池子。有些朋友可能要问了上面的getCurrentCalls函数直接用send(rr)把整个RILRequest全部发送出去了这是什么情况。记得rr里面还带有mSerial这个值的,这个值就可以定位到是哪个RILRequest被发送了。
send(rr)函数将RILRequest发送到RILSender的处理逻辑里面,由handleMessage进行处理。
case EVENT_SEND:
try {
LocalSocket s;
s = mSocket;
synchronized (mRequestList) {
mRequestList.append(rr.mSerial, rr);//将request添加到一个列表中
}
byte[] data;
data = rr.mParcel.marshall();//序列化mParcel里面的内容,注意里面包含request类型和request在池中的id
rr.mParcel.recycle();
rr.mParcel = null;//release resource
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
s.getOutputStream().write(dataLength);//将数据长度和数据内容发送到mSocket里面,其实就是rild这个socket
s.getOutputStream().write(data);
}
还记得我们分析rild的native层的时候,提到的rild的main函数吗?最后会调用RIL_register函数,在这个函数最后会调用:
memcpy(&s_callbacks, callbacks, sizeof (RIL_RadioFunctions));
/* Initialize socket1 parameters */
s_ril_param_socket = {
RIL_SOCKET_1, /* socket_id */
-1, /* fdListen */
-1, /* fdCommand */
PHONE_PROCESS, /* processName */
&s_commands_event, /* commands_event */
&s_listen_event, /* listen_event */
processCommandsCallback, /* processCommandsCallback */
NULL /* p_rs */
};
startListen(RIL_SOCKET_1, &s_ril_param_socket);
这个callbacks会用来初始化s_callbacks,而这个RIL_RadioFunctions类型的callbacks是调用rilInit之后返回的值。也既是调用三方的ril库文件,通过初始化返回的callbacks参数作为值来初始化rild层的s_callbacks参数(记住在reference-ril.c里面也有一个s_callbacks变量,但是为static类型,仅在该文件里面才有效)。
所以这个startlisten函数是在指定socket(RIL_SOCKET_1)上进行监听。看看该函数内部实现:
//Ril.cpp
static void startListen(RIL_SOCKET_ID socket_id, SocketListenParam* socket_listen_p) {
fdListen = android_get_control_socket(socket_name);//在init.rc里面找同名的socket
ret = listen(fdListen, 4);
socket_listen_p->fdListen = fdListen;
/* note: non-persistent so we can accept only one connection at a time */
ril_event_set (socket_listen_p->listen_event, fdListen, false,listenCallback, socket_listen_p);
rilEventAddWakeup (socket_listen_p->listen_event);
}
可以看到针对这个fdListen(其实就是rild这个socket的文件描述符,也就是监听rild这个socket)被放到socket_listen-p(其实就是s_ril_param_socket)里面的listen_event这个ril_event中了。
注意,之前我们就在初始化native层的rild的时候就启动了一个ril_event_loop为函数主体的线程。它会监听rild这个套接字,当监听到数据的时候就会在ril_event_loop这个函数里面触发select这个函数,因为rild这个套接字已经放入了readFds这个FD_SET集合了。检测到之后就会触发
// Check for timeouts
processTimeouts();
// Check for read-ready
processReadReadies(&rfds, n);
// Fire away
firePending();
所以最后调用的firePending,会直接遍历pending_list列表的每个event,并且调用ev->func(ev->fd, 0, ev->param)直接处理自己。ev->param这个参数实际上是在调用ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);时最后一个参数。也就是socket_listen_p,也即是s_ril_param_socket.
在这里监听到这个socket上的变化之后会调用listenCallback来处理。
static void listenCallback (int fd, short flags, void *param) {
SocketListenParam *p_info = (SocketListenParam *)param;
fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);//注意这里的accept函数,接收了套接字rild上面的事件
if(NULL == sapSocket) {
p_info->fdCommand = fdCommand;
p_rs = record_stream_new(p_info->fdCommand, MAX_COMMAND_BYTES);
p_info->p_rs = p_rs;
ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info);
rilEventAddWakeup (p_info->commands_event);
onNewCommandConnect(p_info->socket_id);
}
}
接收到之后,又将这个fdCommand放入到了readFds里面,进行监听。且触发的是p_info(也即是s_ril_param_socket)的响应函数,就是processCommandsCallback函数。
static void processCommandsCallback(int fd, short flags, void *param) {
for (;;) {
/* loop until EAGAIN/EINTR, end of stream, or other error */
ret = record_stream_get_next(p_rs, &p_record, &recordlen);
processCommandBuffer(p_record, recordlen, p_info->socket_id);
}
if (ret == 0 || !(errno == EAGAIN || errno == EINTR)) {
rilEventAddWakeup(&s_listen_event);
onCommandsSocketClosed(p_info->socket_id);
}
}
注意,for循环里面会循环读取p_rs里面的数据,并且将读取出来的p_record传递到processCommandBuffer函数进行处理。
static int processCommandBuffer(void *buffer, size_t buflen, RIL_SOCKET_ID socket_id) {
RequestInfo *pRI;
/* pendingRequestsHook refer to &s_pendingRequests */
RequestInfo** pendingRequestsHook = &s_pendingRequests;
p.setData((uint8_t *) buffer, buflen);
// status checked at end
//注意这个序列化参数的读取顺序跟下面的写入顺序是对应的,所以这个token也就是mSerial了
status = p.readInt32(&request);
status = p.readInt32 (&token);
pRI->token = token;
pRI->pCI = &(s_commands[request]);
pRI->socket_id = socket_id;
pRI->p_next = *pendingRequestsHook;
*pendingRequestsHook = pRI;
/* sLastDispatchedToken = token; */
pRI->pCI->dispatchFunction(p, pRI);
return 0;
}
//ril.java--RILRequest--obtain
static RILRequest obtain(int request, Message result) {
// first elements in any RIL Parcel
rr.mParcel.writeInt(request);
rr.mParcel.writeInt(rr.mSerial);
}
对于当前的RIL_REQUEST_GET_CURRENT_CALLS来说,这个常量值在下面定义:
RILConstants.java:211: int RIL_REQUEST_GET_CURRENT_CALLS = 9;
所以pRI->pCI = &(s_commands[9]);,找到Ril_commands.h中对应id的值为:
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
所以我们知道后面调用的pRI->pCI->dispatchFunction(p, pRI);是调用哪个函数了。
static void dispatchVoid (Parcel& p, RequestInfo *pRI) {
CALL_ONREQUEST(pRI->pCI->requestNumber, NULL, 0, pRI, pRI->socket_id);
}
等价于:
s_callbacks.onRequest(pRI->pCI->requestNumber, NULL, 0, pRI, pRI->socket_id)
所以跳转到reference-ril.c里面去了,会执行onRequest方法里面的如下分支:
case RIL_REQUEST_GET_CURRENT_CALLS:
requestGetCurrentCalls(data, datalen, t);
break;
//Reference-ril.c
static void requestGetCurrentCalls(void *data __unused, size_t datalen __unused, RIL_Token t)
{
ATResponse *p_response;
ATLine *p_cur;
RIL_Call *p_calls;
err = at_send_command_multiline ("AT+CLCC", "+CLCC:", &p_response);
for (countValidCalls = 0, p_cur = p_response->p_intermediates
; p_cur != NULL
; p_cur = p_cur->p_next
) {
err = callFromCLCCLine(p_cur->line, p_calls + countValidCalls);
countValidCalls++;
}
RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, countValidCalls * sizeof (RIL_Call *));
at_response_free(p_response);
RIL_requestTimedCallback (sendCallStateChanged, NULL, &TIMEVAL_CALLSTATEPOLL);
}
其实就是通过at_send_command_multiline向modem发送AT命令,并且将结果存储在p_response中。后续会对将其中的内容解析出来,放入pp_calls里面。最后会调用RIL_onRequestComplete(t, RIL_E_SUCCESS, pp_calls, countValidCalls * sizeof (RIL_Call *))。所以,发送RIL_REQUEST_GET_CURRENT_CALLS命令之后,从modem用AT命令查询到的结果pp_calls就被RIL_onRequestComplete函数返回了。
extern "C" void RIL_onRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) {
pRI = (RequestInfo *)t;
int fd = s_ril_param_socket.fdCommand;
socket_id = pRI->socket_id;
if (pRI->cancelled == 0) {
Parcel p;
//注意这里写入的类型是RESPONSE_SOLICITED,该值在上层的RIL.java的解析函数processResponse里面会读取出来并进行处理的。
p.writeInt32 (RESPONSE_SOLICITED);
p.writeInt32 (pRI->token);
p.writeInt32 (e);
if (response != NULL) {
// there is a response payload, no matter success or not.
ret = pRI->pCI->responseFunction(p, response, responselen);
}
sendResponse(p, socket_id);
}
}
还记得Ril_commands.h里面的数组吗?
{RIL_REQUEST_GET_CURRENT_CALLS, dispatchVoid, responseCallList},
pRI->pCI->responseFunction(p, response, responselen);这个函数对应的就是最后的responseCallList函数。该函数在Ril.cpp里面定义。
主要作用就是将response里面所有的电话信息都保存到序列化参数p里面,而这个参数最终会被sendResponse函数发送出去。
//ril.cpp
static int sendResponse (Parcel &p, RIL_SOCKET_ID socket_id) {
return sendResponseRaw(p.data(), p.dataSize(), socket_id);
}
static int sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_ID socket_id) {
int fd = s_ril_param_socket.fdCommand;
uint32_t header;
header = htonl(dataSize);//主机数转换成无符号长整型的网络字节顺序,因为马上就要通过Socket传播了
ret = blockingWrite(fd, (void *)&header, sizeof(header));
ret = blockingWrite(fd, data, dataSize);
}
下面的blockingWrite就是将数据往fd句柄里面写入,代码如下:
static int blockingWrite(int fd, const void *buffer, size_t len) {
written = write (fd, toWrite + writeOffset, len - writeOffset);
}
那这个地方的fd是哪里冒出来的呢?是否已经被绕晕了,不要怕,我也晕。但是凡事都有蛛丝马迹,需要的是耐心。我们追根溯源看看这个变量。最近的赋值,是在上一级的sendResponseRaw里面fd = s_ril_param_socket.fdCommand。而s_ril_param_socket是在RIL_register(这个函数大家应该很熟悉了吧,在ril.cpp里面,在rild.c的main函数里面被调用)里面,以引用传递的方式被传递给startListen函数了。而后,在startListen里面该变量被重命名为socket_listen_p,并被二人组加入到多路IO复用机制里面了。
//RIL_register
startListen(RIL_SOCKET_1, &s_ril_param_socket);
//startListen函数
ril_event_set (socket_listen_p->listen_event, fdListen, false, listenCallback, socket_listen_p);
所以当触发的时候,该参数作为param被传到响应函数listenCallback中了。
static void listenCallback (int fd, short flags, void *param) {
SocketListenParam *p_info = (SocketListenParam *)param;
fdCommand = accept(fd, (sockaddr *) &peeraddr, &socklen);
if(NULL == sapSocket) {
p_info->fdCommand = fdCommand;//注意这里的fdCommand是接受上层数据的socket
p_info->p_rs = p_rs;
ril_event_set (p_info->commands_event, p_info->fdCommand, 1, p_info->processCommandsCallback, p_info);
rilEventAddWakeup (p_info->commands_event);
onNewCommandConnect(p_info->socket_id);
}
}
所以看到这里,大家就知道这个fd其实就是调用accept,响应上层传入的数据之后的socket。所以这blockwriting其实就是将从modem获取的数据写回到上层去。
我们再次回到上层。接受该消息的就是RIL.java里面的内部类RILReceiver,它是一个Runnable类。这个类在RIL的构造函数里面被初始化,并且被另起了一个线程来运行。
//RIL.java--RILReceiver--run
public void run() {
String rilSocket = "rild";
for (;;) {
try {
s = new LocalSocket();
l = new LocalSocketAddress(rilSocket, LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
}
mSocket = s;
try {
InputStream is = mSocket.getInputStream();
for (;;) {
length = readRilMessage(is, buffer);
p = Parcel.obtain();
p.unmarshall(buffer, 0, length);
p.setDataPosition(0);
processResponse(p);
} } }}
所以很明显可以看到,这个线程就是不停的从rild这个socket里面读取值,并且将读取出来的值序列化成parcel类型,最后用processResponse函数处理该值。
private void processResponse (Parcel p) {
type = p.readInt();
if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
} else if (type == RESPONSE_SOLICITED) {
RILRequest rr = processSolicited (p);
}
}
在RIL_onRequestComplete函数里面,type类型被定义为RESPONSE_SOLICITED。所以会触发下面一个分支。
private RILRequest processSolicited (Parcel p) {
serial = p.readInt();
error = p.readInt();
RILRequest rr;
rr = findAndRemoveRequestFromList(serial);
Object ret = null;
if (error == 0 || p.dataAvail() > 0) {
// either command succeeds or command fails but with data payload
try {switch (rr.mRequest) {
case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
}}
}
if (error == 0) {
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}
}
}
我们来分析一下responseCallList函数:
private Object responseCallList(Parcel p) {
ArrayList<DriverCall> response;
DriverCall dc;
num = p.readInt();
response = new ArrayList<DriverCall>(num);
for (int i = 0 ; i < num ; i++) {
dc = new DriverCall();
dc.state = DriverCall.stateFromCLCC(p.readInt());
dc.index = p.readInt();
response.add(dc);
}
Collections.sort(response);
return response;
}
其实就是读取序列化参数p里面的数据,并且实例化为DriverCall对象,并放入response这个列表,且返回该列表。
下面分析如何处理response的代码:
if (error == 0) {
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();
}
}
是将一个消息发送给它的target进行处理。注意在函数调用中,rr.mResult.obj被赋值为了这个AsyncResult了。一个消息必包含一个message.what和messag.target(也就是handle)。那我们看看这个消息是怎么来的,其实这个rr是通过serial这个rr的id号在列表中找到的,上面我们也提到过这个id号,它是用来标识唯一的RilRequest的。至于这个rr怎么来的,大家看看下面的代码就知道了。
//CallTracker.java
protected void pollCallsWhenSafe() {
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
mCi.getCurrentCalls(mLastRelevantPoll);
}
}
//RIL.java
public void getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
//将这个rr放入列表中了,这个列表用mSerial唯一标识了它的id,这个mSerial也会被传入底层一直到从底层返回,同样也包含了这个mSerial。所以这个是伴随这个RILRequest的整个声明周期的。
send(rr);
}
所以我们知道,这个message的target是CallTracker类或子类,而what参数为EVENT_POLL_CALLS_RESULT。
在实际代码中,以GsmPhone为例,target就换成了GsmCallTracker了。
//GsmCallTracker--handleMessage
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.obj;
if (msg == mLastRelevantPoll) {
handlePollCalls((AsyncResult)msg.obj);
}
注意这个msg.obj实际上在AsyncResult.forMessage(rr.mResult, ret, null)中被赋值为了一个AsyncResult了。
rr.mResult.obj = new AsyncResult(rr.mResult.obj/*userObj*/, ret/*result*/, null/*exception*/);
这个ret就是通过rild这个套接字从native层接收到的结果解析成数据,并且放入ArrayList response。所以这个ret就是很多DriverCall组成的列表啊。
我们下面看看handlePollCalls函数,看他是如何处理返回结果的。
//GsmCallTracker
protected synchronized void handlePollCalls(AsyncResult ar) {
if (ar.exception == null) {
polledCalls = (List)ar.result;//注意这里的赋值
}
Connection newRinging = null; //or waiting
for (int i = 0, curDC = 0, dcSize = polledCalls.size(); i < mConnections.length; i++) {
GsmConnection conn = mConnections[i];
// polledCall list is sparse
if (curDC < dcSize) {
dc = (DriverCall) polledCalls.get(curDC);
}
if (conn == null && dc != null) {
// Connection appeared in CLCC response that we don‘t know about
// 注意这里是判断是否是MO,也就是拨出电话
if (mPendingMO != null && mPendingMO.compareTo(dc)) {
// It‘s our pending mobile originating call
} else {//这就是拨入电话的响应逻辑了。
mConnections[i] = new GsmConnection(mPhone, dc, this, i);//注意这里初始化的GsmConnection
Connection hoConnection = getHoConnection(dc);
if (hoConnection != null) {//这个是针对SRVCC这种类型的电话,所以也不是
// Single Radio Voice Call Continuity (SRVCC) completed mConnections[i].migrateFrom(hoConnection);
// Updating connect time for silent redial cases (ex: Calls are transferred
// from DIALING/ALERTING/INCOMING/WAITING to ACTIVE)
} else if ( mConnections[i].getCall() == mRingingCall ) { // it‘s a ringing call,就是这里了
newRinging = mConnections[i];
} }
hasNonHangupStateChanged = true; } }
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
}
updatePhoneState();
if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) {
mPhone.notifyPreciseCallStateChanged();
}
}
看看mPhone.notifyNewRingConnection(newRinging)函数,就是在这里通知的。这个mPhone其实就是在GsmPhone的构造函数里面实例化GsmCallTracker的时候传入的。最后辗转调用的是GsmPhone的父类里面的函数。这个有点类似模板方法了哈,把部分逻辑过程放在父类里面实现,它所有的子类都公用这段逻辑。
//PhoneBase.java
public void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
return;
AsyncResult ar = new AsyncResult(null/*userObj*/, cn/*result,其实就是mConnections[i] = new GsmConnection(mPhone, dc, this, i)*/, null/*exception*/); mNewRingingConnectionRegistrants.notifyRegistrants(ar);
}
//AsyncResult.java
public /*synchronized*/ void notifyRegistrants(AsyncResult ar)
{ internalNotifyRegistrants(ar.result, ar.exception); }
private synchronized void internalNotifyRegistrants (Object result, Throwable exception)
{
for (int i = 0, s = registrants.size(); i < s ; i++) {
Registrant r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
}}
等价为:
r.internalNotifyRegistrant(mConnections[i] = new GsmConnection(mPhone, dc, this, i), null);
其实就是调用在列表中的每个Registrant来处理从底层传回来的结果。这个很像观察者模式吧,哈哈,把所有的观察者放在一个列表,等事件来的时候,一一通知。
所以这样来看看这些Registrant是在哪里放入PhoneBase里面这个mNewRingingConnectionRegistrants列表的。经过查找,找到下面的地方。
//CallManager.java-->registerForPhoneStates
//这个handler为CallManagerHandler类型。说明从modem返回的值会被该类处理。类型以及在这里指定了
phone.registerForNewRingingConnection(handler, EVENT_NEW_RINGING_CONNECTION,mRegistrantidentifier);
//CallManager.java-->CallManagerHandler
case EVENT_NEW_RINGING_CONNECTION:
Connection c = (Connection) ((AsyncResult) msg.obj).result;
int subId = c.getCall().getPhone().getSubId();
if (getActiveFgCallState(subId).isDialing() || hasMoreThanOneRingingCall(subId)) {
//当前是否有正在拨打的电话,或者是否有另外一个正在呼入的电话
} else { mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
}
看起来并不像是这个地方处理,所以扩大到全项目搜索代码,最后在packages目录下的PstnIncomingCallNotifier.java中找到。(这个名字签名的Pstn不知道到底啥意思)
//从类开头的注释也可以看出来,该类确实用来负责处理拨入的电话PstnIncomingCallNotifier.java
/**
* Listens to incoming-call events from the associated phone object and notifies Telecom upon each
* occurence. One instance of these exists for each of the telephony-based call services.
*/
final class PstnIncomingCallNotifier {
private void registerForNotifications() {
Phone newPhone = mPhoneProxy.getActivePhone();
if (newPhone != null) {
mPhoneBase = newPhone; mPhoneBase.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null); } } }
而这个mHandler对EVENT_NEW_RINGING_CONNECTION的处理为:
case EVENT_NEW_RINGING_CONNECTION:
handleNewRingingConnection((AsyncResult) msg.obj);
break;
//handleNewRingingConnection
private void handleNewRingingConnection(AsyncResult asyncResult) {
Log.d(this, "handleNewRingingConnection");
Connection connection = (Connection) asyncResult.result;
if (connection != null) {
Call call = connection.getCall();
// Final verification of the ringing state before sending the intent to Telecom.
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
}
}
}
/**
* Sends the incoming call intent to telecom.
*/
private void sendIncomingCallIntent(Connection connection) {
Bundle extras = null;
if (connection.getNumberPresentation() == TelecomManager.PRESENTATION_ALLOWED && !TextUtils.isEmpty(connection.getAddress())) {
extras = new Bundle();
Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, connection.getAddress(), null); extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, uri);
} //将通话connection的地址打包进extras。注意这个ID,EXTRA_INCOMING_CALL_ADDRESS
TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(PhoneUtils.makePstnPhoneAccountHandle(mPhoneProxy), extras);
//PhoneUtils.makePstnPhoneAccountHandle的返回值类似等价于下面代码
PhoneUtils.makePstnPhoneAccoutnHandle(mPhoneProxy) = new PhoneAccountHandle(TelephonyConnectionService, mPhoneProxy.getSubId())
}
所以该结果被传到TelecomManager里面去了。
((TelecomManager) mPhoneProxy.getContext().getSystemService(Context.TELECOM_SERVICE)).addNewIncomingCall( PhoneAccountHandle, extras);
//TelecomManager.java
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
try { if (isServiceConnected()) { getTelecomService().addNewIncomingCall(phoneAccount, extras == null ? new Bundle() : extras);
}}}
这个addNewIncomingCall函数最终调用的是TelecomServiceImpl.java类里面的。其实这些方法是在该类的变量:private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub()下面实现的。
//TelecomServiceImpl.java
@Override
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
synchronized (mLock) {
Log.i(this, "Adding new incoming call with phoneAccountHandle %s", phoneAccountHandle);
if (phoneAccountHandle != null && phoneAccountHandle.getComponentName() != null) {
try {
Intent intent = new Intent(TelecomManager.ACTION_INCOMING_CALL);
intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,phoneAccountHandle); intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
if (extras != null) { intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);}
CallIntentProcessor.processIncomingCallIntent(mCallsManager, intent);}}}}
其实就是将传进来的参数打包成Intent,然后通过CallIntentProcessor.processIncomingCallIntent处理掉。
//CallIntentProcessor.java
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
Bundle clientExtras = null;
if (intent.hasExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS)) {
clientExtras = intent.getBundleExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS);
} callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}
上文的callsManager是在TelecomServiceImpl的构造函数里面赋值的。而该变量实际是在TelecomSystem.java的构造函数里面赋值的:
//TelecomSystem.java
public TelecomSystem(
Context context,MissedCallNotifier missedCallNotifier,CallerInfoAsyncQueryFactory callerInfoAsyncQueryFactory, HeadsetMediaButtonFactory headsetMediaButtonFactory,ProximitySensorManagerFactory proximitySensorManagerFactory,InCallWakeLockControllerFactory inCallWakeLockControllerFactory,
ViceNotifier vicenotifier) {
mCallsManager = new CallsManager(mContext,mLock,mContactsAsyncHelper,callerInfoAsyncQueryFactory,mMissedCallNotifier,mPhoneAccountRegistrar,headsetMediaButtonFactory,proximitySensorManagerFactory,inCallWakeLockControllerFactory,mViceNotifier);
}
注意,CallsManager里面有好多参数都是TelecomSystem实例化的实例化的时候传进来的值。这个TelecomSystem是在TelcomService里面进行实例化的,你看到这个实例化的时候一定会大吃一惊!
//TelecomService.java
new TelecomSystem(context,
new MissedCallNotifierImpl(context.getApplicationContext()),
new CallerInfoAsyncQueryFactory() {//注意这个数据库查询类,UI上显示的来电人都是通过这个在数据库中匹配的
@Override
public CallerInfoAsyncQuery startQuery(int token, Context context, String number, CallerInfoAsyncQuery.OnQueryCompleteListener listener, Object cookie) {
Log.i(TelecomSystem.getInstance(), "CallerInfoAsyncQuery.startQuery number=%s cookie=%s",
Log.pii(number), cookie);
return CallerInfoAsyncQuery.startQuery(token, context, number, listener, cookie);
}
},
new HeadsetMediaButtonFactory() {
@Override
public HeadsetMediaButton create(Context context, CallsManager callsManager, TelecomSystem.SyncRoot lock) {
return new HeadsetMediaButton(context, callsManager, lock);
}
},
new ProximitySensorManagerFactory() {
@Override
public ProximitySensorManager create(Context context, CallsManager callsManager) {
return new ProximitySensorManager(context, callsManager);
}
},
new InCallWakeLockControllerFactory() {
@Override
public InCallWakeLockController create(Context context, CallsManager callsManager) {
return new InCallWakeLockController(context, callsManager);
}
},
new ViceNotifier() {
@Override
public ViceNotificationImpl create(Context context, CallsManager callsManager) {
return new ViceNotificationImpl(context.getApplicationContext(), callsManager);
}
})
这里面定义了一堆匿名内部类,部分内容被传至CallsManager类(注意这里是CallsManager而不是CallManager)。至此,我们总算知道了实例化这个CallsManager实例时,里面存放的到底是些什么内容了。所以我们再回到上面的:
//CallIntentProcessor.java
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
//CallsManager.java
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
Uri handle = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
Call call = new Call(mContext,this,mLock,mConnectionServiceRepository,
mContactsAsyncHelper,mCallerInfoAsyncQueryFactory,
handle,//其实这个就是地址或者来电号码。从Connection里面获取的,见之前的代码
null /* gatewayInfo */,null /* connectionManagerPhoneAccount */,
phoneAccountHandle,true /* isIncoming */,false /* isConference */);
call.setIntentExtras(extras);
call.addListener(this);
call.startCreateConnection(mPhoneAccountRegistrar);
}
//packages\services\telecomm\src\com\android\server\telecom\Call.java
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this, phoneAccountRegistrar, mContext);/*mRepository-- CallsManager.java
mConnectionServiceRepository =new ConnectionServiceRepository(mPhoneAccountRegistrar, mContext, mLock, this);*/
mCreateConnectionProcessor.process();
}
//CreateConnectionProcessor.java
void process() {
mAttemptRecords = new ArrayList<>();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
}
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
}
我们先看看CreateConnectionProcessor的简介:
这个类创建一个Connection,这个connection用来放置拨出的电话,或者附着到一个呼入电话上。在两种方式中,这个类会循环编译一系列Connection Services,直到有下列情况发生:
一个connection services返回一个最新创建的connection,因为有一个call被显示给了用户
一个connection service取消了处理进程,call就abort中断了。
因为可以看到上面的 程序中有一个明显的迭代器,所以看看最后一个函数是否对迭代器的数据进行了处理:
//CreateConnectionProcessor.java
private void attemptNextPhoneAccount() {
CallAttemptRecord attempt = null;
if (mAttemptRecordIterator.hasNext()) {
attempt = mAttemptRecordIterator.next();
}
if (mResponse != null && attempt != null) {
PhoneAccountHandle phoneAccount = attempt.connectionManagerPhoneAccount;
ConnectionServiceWrapper service = mRepository.getService(phoneAccount.getComponentName(), phoneAccount.getUserHandle());
if (service == null) {} else { mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(service);
setTimeoutIfNeeded(service, attempt);
service.createConnection(mCall, new Response(service));
}}}
//ConnectionServiceWrapper.java
void createConnection(final Call call, final CreateConnectionResponse response) {
BindCallback callback = new BindCallback() {注意,这个callback就是在下面连接服务成功时候,会触发自己的onSuccess函数};
mBinder.bind(callback, call);
}
//ServiceBinder.java
void bind(BindCallback callback, Call call) {
mCallbacks.add(callback);
if (mServiceConnection == null) {
Intent serviceIntent = new Intent(mServiceAction).setComponent(mComponentName);
ServiceConnection connection = new ServiceBinderConnection(call);
Log.event(call, Log.Events.BIND_CS, mComponentName);
final int bindingFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
final boolean isBound;
if (mUserHandle != null) {
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,mUserHandle);
}}}}
其实这个serviceIntent触发的是”android.telecom.ConnectionService”这个Action,在package/Service/Telephony/AndroidManifest.xml里面可以找到对应的service为TelephonyConnectionService。这个mComponentName的值就没有找到在什么地方了。连接成功之后,就会触发connection的onServiceConnected函数了。
//ServiceBinder&ServiceBinderConnection
public void onServiceConnected(ComponentName componentName, IBinder binder) {
synchronized (mLock) {
mServiceConnection = this;
setBinder(binder);
handleSuccessfulConnection();
}}
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
} }
这个callback就是在上面createConnection函数中创建的内部类如下:
//ConnectionServiceWrapper.java--createConnection
BindCallback callback = new BindCallback() {
public void onSuccess()
{
String callId = mCallIdMapper.getCallId(call);
mPendingResponses.put(callId, response);
GatewayInfo gatewayInfo = call.getGatewayInfo();
Bundle extras = call.getIntentExtras();
if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
gatewayInfo.getOriginalAddress() != null) {
extras = (Bundle) extras.clone(); extras.putString(TelecomManager.GATEWAY_PROVIDER_PACKAGE,gatewayInfo.getGatewayProviderPackageName()); extras.putParcelable(TelecomManager.GATEWAY_ORIGINAL_ADDRESS,gatewayInfo.getOriginalAddress());
}
try { mServiceInterface.createConnection(call.getConnectionManagerPhoneAccount(),callId,
new ConnectionRequest(call.getTargetPhoneAccount(),call.getHandle(),extras,call.getVideoState()),
call.isIncoming(),
call.isUnknown());
}
}};
其实这个mServiceInterface就是绑定ConnectionService的时候反回来的一个IBinder,所以这个引用就是调用的ConnectionService.createConnection了。
//ConnectionService---createConnection
private void createConnection(final PhoneAccountHandle callManagerAccount,final String callId,
final ConnectionRequest request,boolean isIncoming,boolean isUnknown) {
Connection connection = onCreateIncomingConnection(callManagerAccount, request);
Uri address = connection.getAddress(); mAdapter.handleCreateConnectionComplete(callId,request,new ParcelableConnection());
}
这个调用会遍历mAdapter里面的每个IConnectionServiceAdapter,并且执行
adapter.handleCreateConnectionComplete(id, request, connection);
而这个mAdapter是通过调用addAdapter函数进行填充的。而这个函数在ConnectionService唯一调用的地方是在mHandler里面,处理MSG_ADD_CONNECTION_SERVICE_ADAPTER消息的时候。注意这个mHandler和mAdapter都是private的,也就是都是仅限这个类内部访问。这个消息是在mBinder的addConnectionServiceAdapter函数里面触发的。
在ConnectionServiceWrapper里面的setServiceInterface里面会调用
//ConnectionServiceWrapper,setServiceInterface
mServiceInterface = IConnectionService.Stub.asInterface(binder);
addConnectionServiceAdapter(mAdapter);
private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
if (isServiceValid("addConnectionServiceAdapter")) { mServiceInterface.addConnectionServiceAdapter(adapter);
}}
这个adapter函数实际定义在:
//ConnectionServiceWrapper.java
final class ConnectionServiceWrapper extends ServiceBinder {
private final class Adapter extends IConnectionServiceAdapter.Stub {
其实是一个内部类。所以在ConnectionService—createConnection里面调用adapter.handleCreateConnectionComplete(id, request, connection)实际调用的是这个内部类的对应函数。
//ConnectionServiceWrapper.java---Adapter---handleCreateConnectionComplete
public void handleCreateConnectionComplete(String callId,ConnectionRequest request,ParcelableConnection connection) {
if (mCallIdMapper.isValidCallId(callId)) ConnectionServiceWrapper.this.handleCreateConnectionComplete(callId, request, connection);
}
private void handleCreateConnectionComplete(String callId,ConnectionRequest request,ParcelableConnection connection) {
if (connection.getState() == Connection.STATE_DISCONNECTED) {
} else {
// Successful connection
if (mPendingResponses.containsKey(callId)) { mPendingResponses.remove(callId).handleCreateConnectionSuccess(mCallIdMapper, connection);
}}}
而通过搜索,发现在call.java里面有对函数handleCreateConnectionSuccess的实现。
public void handleCreateConnectionSuccess(CallIdMapper idMapper, ParcelableConnection connection) {
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
//设置显示呼叫者名字 setCallerDisplayName(connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation()); setConnectionCapabilities(connection.getConnectionCapabilities());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState()); setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
setExtras(connection.getExtras());
if (mIsUnknown) {
} else if (mIsIncoming) {
// We do not handle incoming calls immediately when they are verified by the connection
// service. We allow the caller-info-query code to execute first so that we can read the
// direct-to-voicemail property before deciding if we want to show the incoming call to
// the user or if we want to reject the call.
mDirectToVoicemailQueryPending = true;
// Timeout the direct-to-voicemail lookup execution so that we dont wait too long before
// showing the user the incoming call screen.
mHandler.postDelayed(mDirectToVoicemailRunnable, Timeouts.getDirectToVoicemailMillis(
mContext.getContentResolver()));
} else {
for (Listener l : mListeners) { l.onSuccessfulOutgoingCall(this,getStateFromConnectionState(connection.getState()));
}
}
}
请注意看if (mIsIncoming)这个分支里面的注释。当我们正在被连接服务(connection service)验证的时候,我们并不立即处理呼入电话。我们允许来电信息查询代码首先执行,这样我们就可以读取是否转到语音邮箱的属性,这样我们可以决定我们是否将来电显示给用户还是直接拒绝。
我们在看看这个作为mDirectToVoicemailRunnable
//Call.java
private final Runnable mDirectToVoicemailRunnable = new Runnable() {
public void run() {
synchronized (mLock) {
processDirectToVoicemail();
}}};
private void processDirectToVoicemail() {
if (mDirectToVoicemailQueryPending) {
if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
setState(CallState.RINGING, "directing to voicemail");
reject(false, null);
} else {
for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
}
}
mDirectToVoicemailQueryPending = false;
}
}
会调用mListeners的onSuccessfulIncomingCall函数。
//CallsManager.java
public void onSuccessfulIncomingCall(Call incomingCall) {
setCallState(incomingCall, CallState.RINGING, "successful incoming call");
if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId()) || hasMaximumDialingCalls() ) {
incomingCall.reject(false, null);
// since the call was not added to the list of calls, we have to call the missed
// call notifier and the call logger manually. mMissedCallNotifier.showMissedCallNotification(incomingCall);
mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE);
} else { if(TelephonyManager.getDefault().getMultiSimConfiguration()== TelephonyManager.MultiSimVariants.DSDA) {
incomingCall.mIsActiveSub = true;
}
addCall(incomingCall); setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
}}
private void addCall(Call call) {
call.addListener(this);
mCalls.add(call);
// TODO: Update mForegroundCall prior to invoking
// onCallAdded for calls which immediately take the foreground (like the first call).
for (CallsManagerListener listener : mListeners) {
listener.onCallAdded(call);
}
updateCallsManagerState();
}
在CallsManagerListener里面,调用里面的onCallAdded如下:
//InCallController.java这个类实现了CallsManagerListenerBase这个类,所以看看这个的onCallAdded
public void onCallAdded(Call call) {
if (!isBoundToServices()) {//在成功绑定了服务之后,这个函数返回值应该就是true了,所以应该走另外一个分支
bindToServices(call);
} else {
Log.i(this, "onCallAdded: %s", call);
// Track the call if we don‘t already know about it.
addCall(call);
for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = toParcelableCall(call, true /* includeVideoProvider */);
try {
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
}}}}
这个会调用InCallService的addCall函数。
//InCallService.java
public void addCall(ParcelableCall call) { mHandler.obtainMessage(MSG_ADD_CALL,call).sendToTarget();
}
case MSG_SET_IN_CALL_ADAPTER:
mPhone = new Phone(newInCallAdapter((IInCallAdapter) msg.obj));
mPhone.addListener(mPhoneListener);
onPhoneCreated(mPhone);
break;
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
break;
//Phone.java
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,parcelableCall.getState(), parcelableCall.isActive());
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall); call.internalUpdate(parcelableCall,mCallByTelecomCallId);
fireCallAdded(call);
}
注意最后的这个inCallService.addCall(parcelableCall),实际触发了一个消息机制。同时注意,还有一个MSG_SET_IN_CALL_ADAPTER消息会触发将mPhoneListener加入到Phone的监听者列表里面。最终该消息会触发 mPhone.internalAddCall。我们看看这个最后的调用函数fireCallAdded(call):
//Phone.java
private void fireCallAdded(Call call) {
for (Listener listener : mListeners) {
listener.onCallAdded(this, call);
}
}
上面我们也提到了,另外一个消息MSG_SET_IN_CALL_ADAPTER,会将一个监听者mPhoneListener加入到Phone的监听列表里面,所以这个循环遍历列表的行为会触发这个mPhoneListener。
//InCallService.java
private Phone.Listener mPhoneListener = new Phone.Listener() {
public void onAudioStateChanged(Phone phone, AudioState audioState) {}
public void onCallAudioStateChanged(Phone phone, CallAudioState callAudioState) { InCallService.this.onCallAudioStateChanged(callAudioState);};
public void onBringToForeground(Phone phone, boolean showDialpad) { InCallService.this.onBringToForeground(showDialpad);}
public void onCallAdded(Phone phone, Call call) {
InCallService.this.onCallAdded(call);}
public void onCallRemoved(Phone phone, Call call) {
InCallService.this.onCallRemoved(call);}
public void onCanAddCallChanged(Phone phone, boolean canAddCall) { InCallService.this.onCanAddCallChanged(canAddCall);}
};
看看上面的,基本上设计到了各种通话属性的变化。而且都是转到InCallService里面进行处理。看看对于onCallAdded的处理。
InCallService里面的onCallAdded是一个空函数,所以会由它的子类来进行处理,它的子类是InCallServiceImpl.java。重点来了,这个子类中的实现为:
//InCallServiceImpl
public class InCallServiceImpl extends InCallService{
public void onCallAdded(Call call) {
CallList.getInstance().onCallAdded(call);
InCallPresenter.getInstance().onCallAdded(call);
}}
我们来看看CallList的onCallAdded函数:
//CallList.java
ublic void onCallAdded(android.telecom.Call telecommCall) {
Call call = new Call(telecommCall);
if (call.getState() == Call.State.INCOMING ||call.getState() == Call.State.CALL_WAITING) {
onIncoming(call, call.getCannedSmsResponses());
} else {
onUpdate(call);
} }
public void onIncoming(Call call, List<String> textMessages) {
for (Listener listener : mListeners) {
listener.onIncomingCall(call);
}
}
上面讲到了一个细节,CallList实际将InCallPresenter实例保存在了listener列表里面。所以这个onIncoming会触发listener.onIncomingCall(call);这个listener则是InCallPresenter,所以最后调用的是如下:
//InCallPresenter.java
public void onIncomingCall(Call call) {
InCallState newState = startOrFinishUi(InCallState.INCOMING);
InCallState oldState = mInCallState;
mInCallState = newState;
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
}
if (InCallServiceImpl.isDsdaEnabled() && (mInCallActivity != null)) {
mInCallActivity.updateDsdaTab();
}
}
注意,上面的startOrFinishUi是关键函数,涉及到显示来电接听的UI弹出流程。这个InCallPresenter很像Google提倡的MVP结构里面的Presenter啊!
综上,CallList的onCallAdded函数会触发来电信息的显示。最后发现,在InCallServiceImpl.java里面,在onCallAdded函数里面会触发CallList的对应函数,也就是会触发来电显示。
标签:
原文地址:http://blog.csdn.net/murphykwu/article/details/51732382