Android 6.0 MT流程
这段负责通话模块的开发,研究了一下telephony模块,网上参考了些资料加上自己的理解,总结了一下android6 0 MT 流程:。
Markdown和扩展Markdown简洁的语法
代码块高亮
图片链接和图片
一. 列表内容
这段负责通话模块的开发,研究了一下telephony模块,网上参考了些资料加上自己的理解,总结了一下android6.0 MT 流程:。
Markdown和扩展Markdown简洁的语法 代码块高亮 图片链接和图片上传 LaTex数学公式 UML序列图和流程图 离线写博客
导入导出Markdown文件gdsfdsfs 丰富的快捷键
先放出6.0的MT时序图大家有个直观感受,下面代码一步步进行分析
第一部分:RIL&&GSMPhone Call状态变化 -& 发出来电通知(frameworks\opt\telephony)
1. framwork/opt/telephony/…/RIL.java
作用:RIL-在本质上就是一个RIL代理,起到一个转发的作用,是 Java概念空间中的***的起点。
RIL接收到RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED消息
private void processUnsolicited (Parcel p) {
switch(response) {
case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
if (RILJ_LOGD) unsljLog(response);
2、然后经由mCallStateRegistrants.notifyRegistrants发出通知
mCallStateRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
BaseCommands.java registerForCallStateChanged() mCallStateRegistrants.add(r);
public void registerForCallStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
//添加到观察者列表
mCallStateRegistrants.add(r);
重点1:这其实是观察者模式的一种实现形式
1.RefistrantList 通知者 2.Registrant 观察者,这是一个一对多的关系,在有事件更新时,凡是在名单上登记过的对象,都会收到通知。
RegistrantList通知者支持对通知者的增加(add/addUnique)删除(remove),并且能够发出通知(notifyRegitrants);而Registrant作为观察者,响应通知者发出的notifyRegistrant通知。
整体上这个消息注册机制分为两部分,消息注册和消息通知。当调用regist方法时将Message存放进去,当其调用notify方法时将所有Message取出并发送到MessageQueue中等待处理。
3. framwork/opt/telephony/…GSMCallTracker.java
作用:GSMCallTracker在本质上是一个Handler。GSMCallTracker是Android的通话管理层。GSMCallTracker建立了ConnectionList来管理现行的通话连接,并向上层提供***调用接口。
查找察者被调用的地方, 两处被响应处理处理,其中一处:GSMCallTracker handleMessage
...//registerForCallStateChanged调用
mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
public void
//响应处理
handleMessage (Message msg) {
case EVENT_CALL_STATE_CHANGE: //MT第一次
//调用父类CallTracker查询Call List方法
pollCallsWhenSafe();
4、pollCallsWhenSafe()方法在CallTracker.java中实现
protected void pollCallsWhenSafe() {
mNeedsPoll =
if (checkNoOperationsPending()) {
mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
//RIL.java中的getCurrentCalls方法
mCi.getCurrentCalls(mLastRelevantPoll);
回到RIL.java getCurrentCalls 将RIL_REQUEST_GET_CURRENT_CALLS 消息封装成RILRequest
类型并发送。
public void getCurrentCalls (Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
RIL.java 有三处接收处理RIL_REQUEST_GET_CURRENT_CALLS消息,真正的逻辑处理在processSolicited方法
private RILRequest processSolicited (Parcel p) {
case RIL_REQUEST_GET_CURRENT_CALLS: ret =
responseCallList(p);
if (rr.mResult != null) {
AsyncResult.forMessage(rr.mResult, ret, null);
rr.mResult.sendToTarget();//发出handler消息通知
6、回到framworks/opt/telephony/…/telephony/gsm/GSMCallTracker.java
rr.mResult.sendToTarget()发出handler消息通知后,会在GSMCallTracker中的handleMessage方法中响应。并且它的消息类型是“EVENT_POLL_CALLS_RESULT”
public void handleMessage (Message msg) {
case EVENT_POLL_CALLS_RESULT:
ar = (AsyncResult)msg.
if (msg == mLastRelevantPoll) {
mNeedsPoll =
mLastRelevantPoll =
handlePollCalls((AsyncResult)msg.obj);
8、handlePollCalls方法根据RIL发出的Call List对象判断Call的状态,并发出不同的通知,
1) 新来电的通知是: phone.notifyNewRingingC
另外两个是
2) 通话断开通知 onDisconnected;
3) Call状态变化通知 phone.notifiyPreciseCallStateChanged.
(当状态改变之后便会通过GsmPhone的notifyPreciseCallStateChanged()方法发起响应)
来电的时候发出的是phone.notifyNewRingConnection通知,进入到notifyNewRingConnection方法
handlePollCalls(){
if (newRinging != null) {
mPhone.notifyNewRingingConnection(newRinging);
9、framworks/opt/telephony/…/telephony/gsm/GSMPhone.java
public void notifyNewRingingConnection(Connection c) {
super.notifyNewRingingConnectionP(c);
调用父类 PhoneBase.java(为com.android.internal.telephony.phone接口实现。)
notifyNewRingingConnectionP()发出来电通知 mNewRingingConnectionRegistrants.notifyRegistrants(ar);
* Notify registrants of a new ringing Connection.
* Subclasses of Phone probably want to replace this with a
* version scoped to their packages
public void notifyNewRingingConnectionP(Connection cn) {
if (!mIsVoiceCapable)
AsyncResult ar = new AsyncResult(null, cn, null);
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
重点2: RegistrantList.java \frameworks\base\core\java\android\os
notifyRegistrants方法实现
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 & i++) {
Registrant
r = (Registrant) registrants.get(i);
r.internalNotifyRegistrant(result, exception);
/*package*/ void internalNotifyRegistrant (Object result, Throwable exception)
Handler h = getHandler();
if (h == null) {
Message msg = Message.obtain();
msg.what =
msg.obj = new AsyncResult(userObj, result, exception);
h.sendMessage(msg);
注册为观察者的方法为:
// Inherited documentation suffices.
public void registerForNewRingingConnection(
Handler h, int what, Object obj) {
checkCorrectThread(h);
mNewRingingConnectionRegistrants.addUnique(h, what, obj);
通过log发现PstnIncomingCallNotifier.java调用registerForNewRingingConnection()
01-05 07:10:05.96
1596 D Telephony: PstnIncomingCallNotifier: handleNewRingingConnection
第二部分:PstnIncomingCallNotifier&&Call 接收Framework层到通知&&准备创建连接
10、packages/services/Telephony/…/PstnIncomingCallNotifier.java(packages\services\telephony)
作用:***来之相关***对象的来电事件和通知Telecom在每次发生的时候,这一实例的存在为了每个***的通话服务
registerForNotifications方法调用registerForNewRingingConnection
private void registerForNotifications() {
Phone newPhone = mPhoneProxy.getActivePhone();
if (newPhone != mPhoneBase) {
unregisterForNotifications();
if (newPhone != null) {
Log.i(this, "Registering: %s", newPhone);
mPhoneBase = newP
//调用registerForNewRingingConnection方法
mPhoneBase.registerForNewRingingConnection(
mHandler, EVENT_NEW_RINGING_CONNECTION, null);
mPhoneBase.registerForCallWaiting(
mHandler, EVENT_CDMA_CALL_WAITING, null);
mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
11、handle 处理EVENT_NEW_RINGING_CONNECTION消息
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
case EVENT_NEW_RINGING_CONNECTION:
handleNewRingingConnection((AsyncResult) msg.obj);
12、从之前的log看: 由handleNewRingingConnection方法,处理新的来电连接。
private void handleNewRingingConnection(AsyncResult asyncResult) {
Log.d(this, "handleNewRingingConnection");
Connection connection = (Connection) asyncResult.
if (connection != null) {
Call call = connection.getCall();
//在发送intent到Telecom之前最后一次验证ringing 状态
if (call != null && call.getState().isRinging()) {
sendIncomingCallIntent(connection);
13、sendIncomingCallIntent方法
发送incoming
call intent到telecom,发送的Connection 类型,里面包括isIncoming getState isRinging等
* Sends the incoming call intent to telecom.
private void sendIncomingCallIntent(Connection connection) {
Bundle extras =
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(TelephonyManager.EXTRA_INCOMING_NUMBER, uri);
TelecomManager.from(mPhoneProxy.getContext()).addNewIncomingCall(
TelecomAccountRegistry.makePstnPhoneAccountHandle(mPhoneProxy), extras);
14、addNewIncomingCall()定义在: framworks/base/telecomm/java/android/telecom/TelecomManager.java
作用:TelecomManager的功能则主要是对TelecomService提供的远程接口的封装,然后提供给应用使用。
来电时触发 addNewIncomingCall方法
@SystemApi
public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) {
if (isServiceConnected()) {
getTelecomService().addNewIncomingCall(
phoneAccount, extras == null ? new Bundle() : extras);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException adding a new incoming call: " + phoneAccount, e);
15、 packages/services/Telecomm/src/com/android/server/telecom/TelecomServiceImpl.java
继承自ITelecomService,TelecomService的接口由TeleComManager封装,并其供给应用使用,
重点2:telecom进程讲解
addNewIncomingCall
新建intent 设定intent 的ACTION 、addFalgs等
* @see android.telecom.TelecomManager#addNewIncomingCall
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
synchronized (mLock) {
long token = Binder.clearCallingIdentity();
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);
} finally {
Binder.restoreCallingIdentity(token);
CallIntentProcessor.java (packages\services\telecomm\src\com\android\server\telecom)
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
19、packages/services/Telecomm/src/com/android/server/telecom/CallsManager.java
CallManager类提供了一个抽象层,以供phoneApp访问和控制call等操作。它实现了Phone接口。CallManager提供呼叫和连接控制以及Channel能力。CallManager提供三种类型的API:
1,呼叫控制和操作,如dial()和hangup();
2,Channel的能力,如canconference();
3,注册通知。接着将Phone注册进mCM,Phone状态改变之后InCallUI就能够收到变化消息了。
void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
Call call = new Call(
mConnectionServiceRepository,
mContactsAsyncHelper,
mCallerInfoAsyncQueryFactory,
null /* gatewayInfo */,
null /* connectionManagerPhoneAccount */,
phoneAccountHandle,
true /* isIncoming */,
false /* isConference */);
call.setIntentExtras(extras);
call.addListener(this);
20、new一个Call 对象 把前面的参数传进来,然后调用call中建立连接的方法startCreateConnection
call.startCreateConnection(mPhoneAccountRegistrar);
21、packages/services/Telecomm/src/com/android/server/telecom/Call.java
作用:封装的一个给定的***在其整个生命周期的各个方面,从***意图被telecom接收开始
开始建立连接队列,一旦完成创建,就应当有一个活动active的连接了存在service里。
void startCreateConnection(PhoneAccountRegistrar phoneAccountRegistrar) {
Preconditions.checkState(mCreateConnectionProcessor == null);
mCreateConnectionProcessor = new CreateConnectionProcessor(this, mRepository, this,
phoneAccountRegistrar, mContext);
mCreateConnectionProcessor.process();
第三部分:ConnectionServicesAdapter&&CallsManager 处理这个创建的连接&&成功来电 CallsManager&&Phone 成功来电&&准备启动界面
22、packages/services/Telecomm/src/com/android/server/telecom/CreateConnectionProcessor.java
void process() {
Log.v(this, "process");
clearTimeout();
mAttemptRecords = new ArrayList&&();
if (mCall.getTargetPhoneAccount() != null) {
mAttemptRecords.add(new CallAttemptRecord(
mCall.getTargetPhoneAccount(), mCall.getTargetPhoneAccount()));
adjustAttemptsForConnectionManager();
adjustAttemptsForEmergency();
mAttemptRecordIterator = mAttemptRecords.iterator();
attemptNextPhoneAccount();
23、service试图建立连接
private void attemptNextPhoneAccount() {
if (mResponse != null && attempt != null) {
Log.i(this, "Trying attempt %s", attempt);
ConnectionServiceWrapper service =
mRepository.getService(
attempt.connectionManagerPhoneAccount.getComponentName());
if (service == null) {
Log.i(this, "Found no connection service for attempt %s", attempt);
attemptNextPhoneAccount();
mCall.setConnectionManagerPhoneAccount(attempt.connectionManagerPhoneAccount);
mCall.setTargetPhoneAccount(attempt.targetPhoneAccount);
mCall.setConnectionService(service);
Log.i(this, "Attempting to call from %s", service.getComponentName());
service.createConnection(mCall, new Response(service));
24、packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java 为拨出的***建立连接,或者attach一个已经存在的来电。
void createConnection(final Call call, final CreateConnectionResponse response) {
mBinder.bind(callback);
25、ServiceBinder.java (packages\services\telecomm\src\com\android\server\telecom)
作用:抽象类用来进行绑定和解除绑定到指定的服务接口的工作。子类提供服务的意图和名称和这个类调用受保护方法在类绑定,未绑定或者失败的时候
执行绑定到服务的操作(如果还没有绑定)然后执行指定的回调方法
void bind(BindCallback callback, Call call) {
Log.d(ServiceBinder.this, "bind()");
// Reset any abort request if we're asked to bind again.
clearAbort();
if (!mCallbacks.isEmpty()) {
// Binding already in progress, append to the list of callbacks and bail out.
mCallbacks.add(callback);
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 isB
if (mUserHandle != null) {
isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
mUserHandle);
isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
if (!isBound) {
handleFailedConnection();
Log.d(ServiceBinder.this, "Service is already bound.");
Preconditions.checkNotNull(mBinder);
handleSuccessfulConnection();
26、上面的执行完之后,顺序执行到onServiceConnected
onServiceConnected
private final class ServiceBinderConnection implements ServiceConnection {
public void onServiceConnected(ComponentName componentName, IBinder binder) {
ThreadUtil.checkOnMainThread();
Log.i(this, "Service bound %s", componentName);//这句log被打印出来了
// Unbind request was queued so unbind immediately.
if (mIsBindingAborted) {
clearAbort();
logServiceDisconnected("onServiceConnected");
mContext.unbindService(this);
handleFailedConnection();
mServiceConnection =
setBinder(binder);
handleSuccessfulConnection();
private void handleSuccessfulConnection() {
for (BindCallback callback : mCallbacks) {
callback.onSuccess();
mCallbacks.clear();
28、回调上面的onSuccess() 执行mServiceInterface.createConnectioncreateConnection的具体实现在ConnectionService.java (frameworks\base\telecomm\java\android\telecom)
作用:一个提供***连接到Android设备上运行的进程。
public void createConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
String id,
ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
//chengzhi
SomeArgs args = SomeArgs.obtain();
args.arg1 = connectionManagerPhoneA
args.arg2 =
args.arg3 =
args.argi1 = isIncoming ? 1 : 0;
args.argi2 = isUnknown ? 1 : 0;
mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
case MSG_CREATE_CONNECTION: {
createConnection(
connectionManagerPhoneAccount,
isIncoming,
isUnknown);
31、这个方法可以被telecom用来创建呼出***或者一个已存在的来电。任何一种情况,telecom都会循环经过一系列的服务和 调用createConnection util a connection service取消或者成功完成创建。
private void createConnection(
final PhoneAccountHandle callManagerAccount,
final String callId,
final ConnectionRequest request,
boolean isIncoming,
boolean isUnknown) {
Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
: isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
: onCreateOutgoingConnection(callManagerAccount, request);
mAdapter.handleCreateConnectionComplete
32、前面建立连接成功了,后面处理成功的连接,后面执行mAdapter.handleCreateConnectionComplete
ConnectionServiceAdapter&CallsManager 处理这个创建的连接&成功来电
33~34.ConnectionServiceAdapter.java (frameworks\base\telecomm\java\android\telecom)
作用:提供iconnectionservice实现与系统的手机应用程序的交互方法。
void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
for (IConnectionServiceAdapter adapter : mAdapters) {
//chengzhi 03
adapter.handleCreateConnectionComplete(id, request, connection);
} catch (RemoteException e) {
CallsManager&Phone 成功来电&准备启动界面
34. packages/services/Telecomm/src/com/android/server/telecom/ConnectionServiceWrapper.java
作用:Telecomm 层的连接管理者
private final class Adapter extends IConnectionServiceAdapter.Stub {
public void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
logIncoming("handleCreateConnectionComplete %s", request);
if (mCallIdMapper.isValidCallId(callId)) {
ConnectionServiceWrapper.this
.handleCreateConnectionComplete(callId, request, connection);
ConnectionServiceAdapterServant.java (frameworks\base\telecomm\java\android\telecom)
private final IConnectionServiceAdapter mStub = new IConnectionServiceAdapter.Stub() {
public void handleCreateConnectionComplete(
String id,
ConnectionRequest request,
ParcelableConnection connection) {
SomeArgs args = SomeArgs.obtain();
args.arg1 =
args.arg2 =
args.arg3 =
mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
34、 handleMessage处理消息 MSG_HANDLE_CREATE_CONNECTION_COMPLETE
// Internal method defined to centralize handling of RemoteException
private void internalHandleMessage(Message msg) throws RemoteException {
switch (msg.what) {
case MSG_HANDLE_CREATE_CONNECTION_COMPLETE: {
SomeArgs args = (SomeArgs) msg.
mDelegate.handleCreateConnectionComplete(
(String) args.arg1,
(ConnectionRequest) args.arg2,
(ParcelableConnection) args.arg3);
} finally {
args.recycle();
35、 如果成功连接 ConnectionServiceWrapper.java (packages\services\telecomm\src\com\android\server\telecom)
private void handleCreateConnectionComplete(
String callId,
ConnectionRequest request,
ParcelableConnection connection) {
// TODO: Note we are not using parameter "request", which is a side effect of our tacit
// assumption that we have at most one outgoing connection attempt per ConnectionService.
// This may not continue to be the case.
if (connection.getState() == Connection.STATE_DISCONNECTED) {
// A connection that begins in the DISCONNECTED state is an indication of
// we handle all failures uniformly
removeCall(callId, connection.getDisconnectCause());
// Successful connection
if (mPendingResponses.containsKey(callId)) {
mPendingResponses.remove(callId)
.handleCreateConnectionSuccess(mCallIdMapper, connection);
重写 handleCreateConnectionSuccess方法
36. packages/services/Telecomm/src/com/android/server/telecom/Call.java handleCreateConnetionSucess()
public void handleCreateConnectionSuccess(
CallIdMapper idMapper,
ParcelableConnection connection) {
Log.v(this, "handleCreateConnectionSuccessful %s", connection);
mCreateConnectionProcessor =
setTargetPhoneAccount(connection.getPhoneAccount());
setHandle(connection.getHandle(), connection.getHandlePresentation());
setCallerDisplayName(
connection.getCallerDisplayName(), connection.getCallerDisplayNamePresentation());
setCallCapabilities(connection.getCapabilities());
setVideoProvider(connection.getVideoProvider());
setVideoState(connection.getVideoState());
setRingbackRequested(connection.isRingbackRequested());
setIsVoipAudioMode(connection.getIsVoipAudioMode());
setStatusHints(connection.getStatusHints());
mConferenceableCalls.clear();
for (String id : connection.getConferenceableConnectionIds()) {
mConferenceableCalls.add(idMapper.getCall(id));
if (mIsUnknown) {
for (Listener l : mListeners) {
l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection.getState()));
} 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 =
// 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()));
for (Listener l : mListeners) {
l.onSuccessfulOutgoingCall(this,
getStateFromConnectionState(connection.getState()));
37、 Runnable mDirectToVoicemailRunnable
private final Runnable mDirectToVoicemailRunnable = new Runnable() {
public void run() {
processDirectToVoicemail();
38、processDirectToVoicemail
final class Call implements CreateConnectionResponse {
* Listener for events on the call.
interface Listener {
void onSuccessfulIncomingCall(Call call);
private void processDirectToVoicemail() {
if (mDirectToVoicemailQueryPending) {
if (mCallerInfo != null && mCallerInfo.shouldSendToVoicemail) {
Log.i(this, "Directing call to voicemail: %s.", this);
// TODO: Once we move State handling from CallsManager to Call, we
// will not need to set STATE_RINGING state prior to calling reject.
setState(CallState.RINGING);
reject(false, null);
// TODO: Make this class (not CallsManager) responsible for changing
// the call state to STATE_RINGING.
// TODO: Replace this with state transition to STATE_RINGING.
for (Listener l : mListeners) {
l.onSuccessfulIncomingCall(this);
mDirectToVoicemailQueryPending =
39. package/services/Telecomm/src/com/android/server/telecom/CallsManager.java
39.1@Override onSuccessfulIncomingCall if 判断后 addCall()
public final class CallsManager extends Call.ListenerBase {
public void onSuccessfulIncomingCall(Call incomingCall) {
Log.d(this, "onSuccessfulIncomingCall");
setCallState(incomingCall, CallState.RINGING);
if (hasMaximumRingingCalls(incomingCall.getTargetPhoneAccount().getId())) {
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);
incomingCall.mIsActiveSub =
addCall(incomingCall);
setActiveSubscription(incomingCall.getTargetPhoneAccount().getId());
39.2 addCall()
* Adds the specified call to the main list of live calls.
* @param call The call to add.
private void addCall(Call call) {
Log.v(this, "addCall(%s)", 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);
updateForegroundCall();
第四部分:CallList&&InCallActivity 开始启动界面 &&显示来电
40、package/services/Telecomm/src/com/android/server/telecom/InCallController.java
作用:结合并提供服务,通过它可以将更新发送到呼叫程序。这类被创建和拥有的callsmanager保持绑定到(被调用的应用程序中实现)。
重写onCallAdded &&
public void onCallAdded(Call call) {
if (!isBoundToServices()) {
bindToServices(call);
adjustServiceBindingsForEmergency();
Log.i(this, "onCallAdded: %s", call);
// Track the call if we don't already know about it.
addCall(call);
for (Map.Entry entry : mInCallServices.entrySet()) {
ComponentName componentName = entry.getKey();
IInCallService inCallService = entry.getValue();
ParcelableCall parcelableCall = toParcelableCall(call,
true /* includeVideoProvider */);
inCallService.addCall(parcelableCall);
} catch (RemoteException ignored) {
41、bindToServices & bindToInCallService
InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
private class InCallServiceConnection implements ServiceConnection {
/** {@inheritDoc} */
@Override public void onServiceConnected(ComponentName name, IBinder service) {
Log.d(this, "onServiceConnected: %s", name);
onConnected(name, service);
private void onConnected(ComponentName componentName, IBinder service) {
addCall(call);
43. framworks/base/telecomm/java/android/telecom/InCallService.java
作用:这个服务可以被任何希望提供管理***的用户界面的应用实现,
当那个服务存在一个***telecom就去绑定这个服务并用它去通知任何活动状态和最近断开的呼叫的被调用的应用
/** Manages the binder calls so that the implementor does not need to deal with it. */
private final class InCallServiceBinder extends IInCallService.Stub {
public void setInCallAdapter(IInCallAdapter inCallAdapter) {
mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
public void addCall(ParcelableCall call) {
mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
44. handleMessage 处理消息 MSG_ADD_CALL
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message msg) {
if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
switch (msg.what) {
case MSG_SET_IN_CALL_ADAPTER:
mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
onPhoneCreated(mPhone);
case MSG_ADD_CALL:
mPhone.internalAddCall((ParcelableCall) msg.obj);
45. framworks/base/telecomm/java/android/telecom/Phone.java
作用:一个统一的虚拟设备提供语音手段(和其他)设备上的通信。
internalAddCall()
final void internalAddCall(ParcelableCall parcelableCall) {
Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.mIsActiveSub);
mCallByTelecomCallId.put(parcelableCall.getId(), call);
mCalls.add(call);
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
45.1 fireCallAdded()
private void fireCallAdded(Call call) {
for (Listener listener : mListeners) {
listener.onCallAdded(this, call);
46、onCallAdded()@SystemApi系统Api,一个空的实现方法 其他使用的地方会 @Override
@SystemApi
public final class Phone {
public abstract static class Listener {
public void onCallAdded(Phone phone, Call call) { }
47. pacakge/apps/InCallUI/src/com/android/incallui/CallList.java
作用:保持主动呼叫的列表和通知感兴趣的类关于这个列表的变化,因为他们是从堆栈收到***,
对这个类变化的主要听众是InCallPresenter
onCallAdded
* Static singleton accessor method.
public static CallList getInstance() {
private Phone.Listener mPhoneListener = new Phone.Listener() {
public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
Call call = new Call(telecommCall);
if (call.getState() == Call.State.INCOMING) {
onIncoming(call, call.getCannedSmsResponses());
onUpdate(call);
48、执行了下面的方法,但再往后的步骤不是从这里走的。
onIncoming()
* Called when a single call has changed.
public void onIncoming(Call call, List textMessages) {
Log.d(this, "onIncoming - " + call);
// Update active subscription from call object. it will be set by
// Telecomm service for incoming call and whenever active sub changes.
if (call.mIsActiveSub) {
long sub = call.getSubId();
Log.d(this, "onIncoming - sub:" + sub + " mSubId:" + mSubId);
if (sub != mSubId) {
setActiveSubscription(sub);
if (updateCallInMap(call)) {
Log.i(this, "onIncoming - " + call);
updateCallTextMap(call, textMessages);
for (Listener listener : mListeners) {
listener.onIncomingCall(call);
49. //pacakge/apps/InCallUI/src/com/android/incallui/InCallPresenter.java
作用:接受来至CallList的更新并通知InCallActivity(UI)的变化。负责为一个新的呼叫启动活动和当通话断开时结束activity
onIncomingCall是一个接口以下是它的实现
* Called when there is a new incoming call.
* @param call
public void onIncomingCall(Call call) {
InCallState newState = startOrFinishUi(InCallState.INCOMING);
InCallState oldState = mInCallS
Log.i(this, "Phone switching state: " + oldState + " -& " + newState);
mInCallState = newS
for (IncomingCallListener listener : mIncomingCallListeners) {
listener.onIncomingCall(oldState, mInCallState, call);
if (CallList.getInstance().isDsdaEnabled() && (mInCallActivity != null)) {
mInCallActivity.updateDsdaTab();
50、startUi
showInCall(false /* showDialpad */, !showAccountPicker /* newOutgoingCall */);
51、showInCall
public void showInCall(final boolean showDialpad, final boolean newOutgoingCall) {
Log.i(this, "Showing InCallActivity");
mContext.startActivity(getInCallIntent(showDialpad, newOutgoingCall));
以下是MT流程的类图,我们就根据这个图做下最后总结
加粗 Ctrl + B 斜体 Ctrl + I 引用 Ctrl + Q 插入链接 Ctrl + L 插入代码 Ctrl + K 插入图片 Ctrl + G 提升标题 Ctrl + H 有序列表 Ctrl + O 无序列表 Ctrl + U 横线 Ctrl + R 撤销 Ctrl + Z 重做 Ctrl + Y
Markdown及扩展
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 ——
使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个等,详细语法参考帮助?。
本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考.
Markdown Extra 表格语法:
可以使用冒号来定义对齐方式:
Markdown Extra 定义列表语法: 项目1 项目2 定义 A 定义 B 项目3 定义 C
代码块语法遵循标准markdown代码,例如:
@requires_authorization
def somefunc(param1='', param2=0):
'''A docstring'''
if param1 & param2: # interesting
print 'Greater'
return (param2 - param1 + 1) or None
class SomeClass:
&&& message = '''interpreter
... prompt'''
生成一个脚注。
使用MathJax渲染LaTex 数学公式.
行内公式,数学公式为:&G(n)=(n?1)!?n&N。 块级公式:
x=?b&b2?4ac???????&2a
可以渲染序列图:
Created with Rapha?l 2.1.0张三张三李四李四嘿,小四儿, 写博客了没?李四愣了一下,说:忙得吐血,哪有时间写。
或者流程图:
Created with Rapha?l 2.1.0开始我的操作确认?结束yesno
离线写博客
即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的中输入即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。
用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。
博客发表后,本地缓存将被删除。
用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。
注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱。
浏览器兼容
目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。 IE9以下不支持 IE9,10,11存在以下问题
不支持离线功能 IE9不支持文件导入导出 IE10不支持拖拽文件导入