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进行具体的通知和取消通知。