一、总览
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 ,执行
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);
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() 函数
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( 非第一次 )
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
// 建立事件循环线程
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));
...
}
第三部分、第四部分:猫相关的各种状态的监听和通知机制/通话相关的图标变换的工作原理。
网络状态, edge,gprs 图标的处理
a 、注册监听部分
==>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 流程:
=>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);// 启动轮询,看是否成功连接 gprs
checkPPP()// 每隔 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++ 部分代码的角度分析
= >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();
}
第六部分:通话相关的语音通路切换原理、震动接口
6 、语音通路
6.1 、设置语音通路的路由
目前我们有两处处理 :
a 、 CallTracker.java 中的
handlePollCalls ()
检测到+ clcc 返回的电话列表中有状态为 DriverCall.State.ALERTING( 表示拨打电话后,对方已经振铃 ) ,此时需要设置语音通路为 MODE_IN_CALL
b 、 PhoneUtils.java 中 setAudioMode ()函数
c 、调用通路分析
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 中被实例化。
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");
6.2 、来电播放振铃 , 挂断或接听停止振铃。
==>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 服务
7 、通话相关的 notification 服务。
7.1 、 NotificationMgr
==>PhoneApp.java
onCreate()
NotificationMgr.init(this)//NotificationMgr.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 、根据是否是电话状态,更新状态栏图表和通知列表(可能是激活,蓝牙,保持等)
7.2 、 CallNotifier
==>PhoneApp.java
onCreate()
notifier = new CallNotifier(this, phone, ringer, mBtHandsfree);// 此类主要是监听通话相关的事件,然后进行例如来电播放铃声,震动。挂断、接听停止振铃等(调用 Ringer 类实现此功能 ) ,根据不同的状态调用调用 NotificationMgr 进行具体的通知和取消通知。
第八部分: 通话相关的各种 server
电话通信相关的服务:
(1) 、从 ServiceManager 得到的:
a 、 wifiService
b 、 PhoneInterfaceManager
c 、 PhoneSubInfo
d 、 SimPhoneBookInterfaceManager
e 、 SimSmsInterfaceManager
f 、 TelephonyRegistry
g 、 NetStatService
h 、 ConnectivityService
(2) 、从 ApplicationContext 得到的:
a 、 TelephonyManager
原文地址 http://blog.youkuaiyun.com/Yangcg/archive/2009/10/28/4738848.aspx