您的位置:首页 > 移动开发 > Android开发

android 电话接听流程解析

2013-03-29 15:52 447 查看
Andriod通话处理流程

一、总览 
        1、从java端发送at命令的处理流程。 

        2、unsolicited 消息从modem上报到java的流程。 

        3、猫相关的各种状态的监听和通知机制。 

        4、通话相关的图标变换的工作原理。 

        5、gprs拨号上网的通路原理。 

        6、通话相关的语音通路切换原理、震动接口。 

        7、通话相关的notification服务。 

        8、通话相关的各种server。 

        第一部分:从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.digits,执行 

java代码:

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() //如果为紧急号码马上启动intent.setClass(this, InCallScreen.class); startActivity(intent); 

java代码:

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()); 

if (LOGV) Log.v(TAG, "Broadcasting intent " + broadcastIntent + "."); 

sendOrderedBroadcast(broadcastIntent, PERMISSION, null, 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消息。找到OutgoingCallReceiver,执行 onReceive()函数

java代码:

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部分流程 

onCreate(第一次)/onNewIntent(非第一次) 

java代码:

internalResolveIntent 

placeCall(intent); 

PhoneUtils.placeCall(mPhone, number, intent.getData()); 

phone.dial(number); 

mCT.dial(newDialString); 

dial(dialString, CommandsInterface.CLIR_DEFAULT); 

cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());//obtainCompleteMessage(EVENT_OPERATION_COMPLETE); 

send(rr); 

msg = mSender.obtainMessage(EVENT_SEND, rr); 

acquireWakeLock(); 

msg.sendToTarget(); 

RILSender.handleMessage() 

case EVENT_SEND: 

... s.getOutputStream().write(dataLength); 

s.getOutputStream().write(data);//从这里流程跑到下面ril.cpp中监听部份 

复制代码

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

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

       rild.c->main() 

       (1)、RIL_startEventLoop 

java代码:

//建立事件循环线程 

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 

java代码:

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

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); 

java代码:

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请求

java代码:

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"等 

java代码:

readerLoop() 

line = readline(); 

processLine(line); 

handleFinalResponse(line); 

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

复制代码

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

java代码:

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++部份 

java代码:

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部份

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)); 

... 



复制代码

       第三部分、第四部分:猫相关的各种状态的监听和通知机制/通话相关的图标变换的工作原理。 网络状态,edge,gprs图标的处理

       a、注册监听部分

java代码:

==>SystemServer.java 

init2() 

Thread thr = new ServerThread(); 

thr.setName("android.server.ServerThread"); 

thr.start(); 

ServerThread.run() com.android.server.status.StatusBarPolicy.installIcons(context, statusBar); 

sInstance = new StatusBarPolicy(context, service); 

// phone_signal 

mPhone = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 

mPhoneData = IconData.makeIcon("phone_signal", 

null, com.android.internal.R.drawable.stat_sys_signal_null, 0, 0); 

mPhoneIcon = service.addIcon(mPhoneData, null); 

// register for phone state notifications. 

((TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE)).listen(mPhoneStateListener, 

PhoneStateListener.LISTEN_SERVICE_STATE 

| PhoneStateListener.LISTEN_SIGNAL_STRENGTH 

| PhoneStateListener.LISTEN_CALL_STATE 

| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE 

| PhoneStateListener.LISTEN_DATA_ACTIVITY); 

//实际是调用的是TelephonyRegistry.listen,此listen函数会将Iphonestatelistener添加到对应的的handler数组中,到时来了事件会轮询回调。 

// data_connection 

mDataData = IconData.makeIcon("data_connection", null, com.android.internal.R.drawable.stat_sys_data_connected_g, 0, 0); 

mDataIcon = service.addIcon(mDataData, null); 

service.setIconVisibility(mDataIcon, false); 

b、事件通知部分 

==>PhoneFactory.java 

makeDefaultPhones() 

sPhoneNotifier = new DefaultPhoneNotifier(); 

useNewRIL(context); 

phone = new GSMPhone(context, new RIL(context), sPhoneNotifier); 

for example 

==>DataConnectionTracker.java 

notifyDefaultData(String reason) 

phone.notifyDataConnection(reason); 

mNotifier.notifyDataConnection(this, reason); 

==>DefaultPhoneNotifier.java 

mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 

"telephony.registry")); 

mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), 

sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), 

sender.getInterfaceName(null)); 

///////////////////////////////////////////////////////////////////////////////////////

   第四部分:gprs拨号上网的通路原理。 
       上层java程序调用gprs流程: 

java代码:

=>PhoneApp.java 

onCreate() 

PhoneFactory.makeDefaultPhones(this); 

phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier); 

mDataConnection = new DataConnectionTracker (this); 

createAllPdpList();//建立缺省pdpconnection 

pdp = new PdpConnection(phone); 

dataLink = new PppLink(phone.mDataConnection); 

dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); 

//某个条件触发执行 

trySetupData(String reason) 

setupData(reason); 

pdp = findFreePdp(); 

Message msg = obtainMessage(); 

msg.what = EVENT_DATA_SETUP_COMPLETE; 

msg.obj = reason; 

pdp.connect(apn, msg); 

phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password, 

obtainMessage(EVENT_SETUP_PDP_DONE)); 

//收到EVENT_SETUP_PDP_DONE消息 

=>pdpconnection.java 

handleMessage() 

case EVENT_SETUP_PDP_DONE: 

dataLink.connect();//dataLink是pppLink.java 

SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务 

poll.what = EVENT_POLL_DATA_CONNECTION; 

sendMessageDelayed(poll, POLL_SYSFS_MILLIS);//启动轮询,看是否成功连接gprscheckPPP()//每隔5秒轮询,看是否连接成功,或断开 

//如果已经连接 

mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP); 

//执行到pdpconnection.handleMessage() 

case EVENT_LINK_STATE_CHANGED 

onLinkStateChanged(ls); 

case LINK_UP: 

notifySuccess(onConnectCompleted); 

onCompleted.sendToTarget(); 

//执行dataConnectionTracker.java的handleMessage() 

case EVENT_DATA_SETUP_COMPLETE 

notifyDefaultData(reason); 

setupDnsProperties(); 

setState(State.CONNECTED); 

phone.notifyDataConnection(reason); 

startNetStatPoll(); 

resetPollStats(); 

复制代码

       1、读取发送出去的包数和接受到的包数 
       2、如果发送的数据包且没有收到应答包数n大于等于看门狗追踪的限定包数。 
       2.1、开始轮询pdp context list,尝试恢复网络连接 
       2.2、如果轮询24次后还没有联通网络则停止网络状态轮询,进行一次ping实验。 
       2.2.1、如果ping成功则,重新进行网络状态轮询,否则发送EVENT_START_RECOVERY事件。

          // reset reconnect timer 
        nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; 
       着重c++部分代码的角度分析

java代码:

=>DataConnectionTracker.java 

trySetupData(String reason) 

setupData(reason); 

=>PdpConnection.java 

pdp.connect(apn, msg); 

=>RIL.JAVA 

phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password, 

obtainMessage(EVENT_SETUP_PDP_DONE)); 

send(rr); 

//send socket to RIL 

//enter c++ layer 

=>ril.cpp 

processCommandsCallback (int fd, short flags, void *param) 

processCommandBuffer(p_record, recordlen); 

status = p.readInt32(&request); 

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

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

dispatchStrings(); 

s_callbacks.onRequest(pRI->pCI->requestNumber, pStrings, datalen, pRI); 

=>reference-ril.c 

onRequest(); 

requestSetupDefaultPDP(data, datalen, t); 

err = write_at_to_data_channel("ATD*99***1#",1); 

//after a while.get "connect" from data channel,so need to send socket message to java layer. 

p.writeInt32 (RESPONSE_SOLICITED); 

p.writeInt32 (pRI->token);//the serial No in the request list. 

errorOffset = p.dataPosition(); 

p.writeInt32 (e); 

if (e == RIL_E_SUCCESS) { 

/* process response on success */ 

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

/* if an error occurred, rewind and mark it */ 

if (ret != 0) { 

p.setDataPosition(errorOffset); 

p.writeInt32 (ret); 





sendResponse(p); 

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

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

blockingWrite(fd, data, dataSize); 

=>RIL.JAVA 

RILReceiver.run(); 

length = readRilMessage(is, buffer); 

p = Parcel.obtain(); 

p.unmarshall(buffer, 0, length); 

p.setDataPosition(0); 

processResponse(p); 

processSolicited (p); 

serial = p.readInt(); 

error = p.readInt(); 

rr = findAndRemoveRequestFromList(serial); 

ret = responseStrings(p); 

if (rr.mResult != null) { 

AsyncResult.forMessage(rr.mResult, ret, null); 

rr.mResult.sendToTarget(); 



=>pdpConnection.java 

handleMessage() 

case EVENT_SETUP_PDP_DONE: 

... 

dataLink.connect(); 

=>pppLink.java 

SystemProperties.set(PROPERTY_PPPD_EXIT_CODE, ""); 

SystemService.start(SERVICE_PPPD_GPRS);//启动pppd_grps服务 

poll.what = EVENT_POLL_DATA_CONNECTION; 

sendMessageDelayed(poll, POLL_SYSFS_MILLIS); 

dataConnection.state = State.CONNECTING; 

handleMessage() 

case EVENT_POLL_DATA_CONNECTION 

checkPPP(); 

if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length) 

|| ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING, 

UNKNOWN_ASCII_STRING.length) && dataConnection.state == State.CONNECTING) 

if (mLinkChangeRegistrant != null) { 

mLinkChangeRegistrant.notifyResult(LinkState.LINK_UP); 

=>pdpConnection.java 

handleMessage() 

case EVENT_LINK_STATE_CHANGED: 

DataLink.LinkState ls = (DataLink.LinkState) ar.result; 

onLinkStateChanged(ls); 

case LINK_UP: 

notifySuccess(onConnectCompleted); 

AsyncResult.forMessage(onCompleted); 

onCompleted.sendToTarget(); 

=>DataConnectionTracker.java 

handleMessage() 

case EVENT_DATA_SETUP_COMPLETE: 

... SystemProperties.set("gsm.defaultpdpcontext.active", "true"); 

notifyDefaultData(reason); 

setupDnsProperties();

//设置dns,gw,我们的实现方式是在pppd中设置的,不用pppd拨号的适用。 

setState(State.CONNECTED); 

phone.notifyDataConnection(reason); 

mNotifier.notifyDataConnection(this, reason); 

=>DefaultPhoneNotifier.java 

//mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 

"telephony.registry"));构造函数中初始化了mRegistry mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), 

sender.getInterfaceName(null)); 

startNetStatPoll(); 



//////////////////////////////////////////////////////////////////////////////////

 第五部分:通话相关的语音通路切换原理、震动接口 
        5、语音通路 
        5.1、设置语音通路的路由 
        目前我们有两处处理: 

        a、CallTracker.java中的handlePollCalls()检测到+clcc返回的电话列表中有状态为DriverCall.State.ALERTING(表示拨打电话后,对方已经振铃),此时需要设置语音通路为MODE_IN_CALL 
        b、PhoneUtils.java中setAudioMode()函数 
        c、调用通路分析 

java代码:

AudioManager audioManager = (AudioManager) context.getSystemService 

(Context.AUDIO_SERVICE); 

audioManager.setMode(mode); 

AudioManager.setMode(mode); 

AudioService.setMode(mode); 

AudioSystem.setMode(mode);(native function) 

android_media_AudioSystem.cpp==>android_media_AudioSystem_setMode() 

AudioSystem.cpp==>setMode() 

const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); 

binder = sm->getService(String16("media.audio_flinger")); 

... 

gAudioFlinger = interface_cast<IAudioFlinger>(binder); 

... 

return gAudioFlinger; 

复制代码

        通过查找“media.audio_flinger”发现AudioFlinger.cpp==>instantiate()//Main_mediaserver.cpp中被实例化。      

java代码:

defaultServiceManager()->addService(String16("media.audio_flinger"), new AudioFlinger()); 

mAudioHardware = AudioHardwareInterface::create(); 

LOGV("Creating Vendor Specific AudioHardware"); 

hw = createAudioHardware(); 

return new AudioHardwareMarvell(); 

return af->setMode(mode); 

AudioHardwareLittle.cpp==>setMode(mode) 

doRouting(); 

enable_incall_headphone()//or others... 

system("alsactl -f /etc/alsactl/asound.state_none restore"); 

system("alsactl -f /etc/alsactl/asound.state_headset_r_s restore"); 

复制代码

       5.2、来电播放振铃,挂断或接听停止振铃。 

java代码:

==>Phone.app 

onCreate() 

ringer = new Ringer(phone); 

Vibrator mVibrator = new Vibrator(); 

mService = IHardwareService.Stub.asInterface(ServiceManager.getService("hardware")); 

notifier = new CallNotifier(this, phone, ringer, mBtHandsfree); 

mPhone.registerForIncomingRing(this, PHONE_INCOMING_RING, null); 

mPhone.registerForPhoneStateChanged(this, PHONE_STATE_CHANGED, null); 

mPhone.registerForDisconnect(this, PHONE_DISCONNECT, null); 

... 

case PHONE_INCOMING_RING: 

mRinger.ring(); 

mHardwareService.setAttentionLight(true); 

mVibratorThread.start(); 

while (mContinueVibrating) { 

mVibrator.vibrate(VIBRATE_LENGTH); 

SystemClock.sleep(VIBRATE_LENGTH + PAUSE_LENGTH); 



... 

makeLooper(); 

mRingHandler.sendEmptyMessage(PLAY_RING_ONCE); 

... 

case PLAY_RING_ONCE: 

PhoneUtils.setAudioMode(mContext,AudioManager.MODE_RINGTONE); 

r.play(); 

... 

case PHONE_DISCONNECT: 

case PHONE_STATE_CHANGED: 

... 

mRinger.stopRing(); 

Message msg = mRingHandler.obtainMessage(STOP_RING); 

msg.obj = mRingtone; 

mRingHandler.sendMessage(msg); 

case STOP_RING: 

r.stop(); 

getLooper().quit(); 

...mVibrator.cancel(); 

复制代码

        第六部分:通话相关的notification服务 
        6、通话相关的notification服务。 
        6.1、NotificationMgr 
        ==>PhoneApp.java 
        onCreate() 
        NotificationMgr.init(this)//NotificationMgr.java//此类主要负责电话通知的具体表现(通知和取消通知),未接图标、通话中、蓝牙激活中、保持中,静音、免提等。封装了简单的瞬间显示文本消息的功能。提供漫游数据连接禁止的通知封装和漫游数据连接允许时取消通知 

java代码:

sMe = new NotificationMgr(context); 

mNotificationMgr = (NotificationManager) 

context.getSystemService(Context.NOTIFICATION_SERVICE); 

mStatusBar = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); //主要用于显示静音和

复制代码

        speaker状态的图表(在状态条右边显示) 
        sMe.updateNotifications();//主要功能是: 
        1、查询是否有未读的未接听电话,并显示到状态栏图标,和通知列表 
        2、根据是否是电话状态,更新状态栏图表和通知列表(可能是激活,蓝牙,保持等) 

         6.2、CallNotifier 
         ==>PhoneApp.java 
         onCreate() 
         notifier = new CallNotifier(this, phone, ringer, mBtHandsfree);//此类主要是监听通话相关的事件,然后进行例如来电播放铃声,震动。挂断、接听停止振铃等(调用Ringer类实现此功能),根据不同的状态调用调用NotificationMgr进行具体的通知和取消通知。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: