首页 > 代码库 > Android7.0 Phone应用源码分析(三) phone拒接流程分析
Android7.0 Phone应用源码分析(三) phone拒接流程分析
接上篇博文:Android7.0 Phone应用源码分析(二) phone来电流程分析
今天我们再来分析下Android7.0 的phone的拒接流程
下面先来看一下拒接电话流程时序图
步骤1:滑动按钮到拒接图标,会调用到AnswerFragment的onDecline方法
com.android.incallui.AnswerFragment
public void onDecline(Context context) { getPresenter().onDecline(context); }
最后是调用到AnswerPresenteronDecline方法
com.android.incallui.AnswerPresenter public void onDecline(Context context) { Log.d(this, "onDecline " + mCallId); if (mCall.getSessionModificationState() == Call.SessionModificationState.RECEIVED_UPGRADE_TO_VIDEO_REQUEST) { InCallPresenter.getInstance().declineUpgradeRequest(context); } else { TelecomAdapter.getInstance().rejectCall(mCall.getId(), false, null); } }
步骤2:进入TelecomAdapter的rejectCall方法
com.android.incallui.TelecomAdaptervoid rejectCall(String callId, boolean rejectWithMessage, String message) { android.telecom.Call call = getTelecomCallById(callId); if (call != null) { call.reject(rejectWithMessage, message); } else { Log.e(this, "error rejectCall, call not in call list: " + callId); }}
TelecomAdapter是incallui与telecom通信的代理类,这里通过callid取出对应的Call对象(android.telecom.Call)
步骤3:调用到framework里Call的reject方法
android.telecom.Callpublic void reject(boolean rejectWithMessage, String textMessage) { mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); }
这里mInCallAdapter是android.telecom.InCallAdapter类,是在Call对象创建的时候由外部传入的参数
在telecom绑定InCallService服务的时候,会传递一个AIDL接口对象,InCallService会生成InCallAdapter对象来保存这个接口对象
步骤4:InCallAdapter的rejectCall方法
android.telecom.InCallAdapter
public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) { try { mAdapter.rejectCall(callId, rejectWithMessage, textMessage); } catch (RemoteException e) { } }
mAdapter就是incallui与telecom通信的AIDL接口
步骤5:跨进程调用进入telecom进程,该AIDL接口具体实现类是InCallAdapter,虽然类名一样但是不同的包名,这里需要注意一下
com.android.server.telecom.InCallAdapter public void rejectCall(String callId, boolean rejectWithMessage, String textMessage) { try { Log.startSession("ICA.rC", mOwnerComponentName); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { Log.d(this, "rejectCall(%s,%b,%s)", callId, rejectWithMessage, textMessage); Call call = mCallIdMapper.getCall(callId); if (call != null) { mCallsManager.rejectCall(call, rejectWithMessage, textMessage); } else { Log.w(this, "setRingback, unknown call id: %s", callId); } } } finally { Binder.restoreCallingIdentity(token); } } finally { Log.endSession(); } }
这里同样是根据callid取出对应Call(com.android.server.telecom.Call),最后调用CallsManager的rejectCall方法传入call
步骤6:CallsManager的rejectCall方法
com.android.server.telecom.CallsManagerpublic void rejectCall(Call call, boolean rejectWithMessage, String textMessage) { if (!mCalls.contains(call)) { Log.i(this, "Request to reject a non-existent call %s", call); } else { for (CallsManagerListener listener : mListeners) { listener.onIncomingCallRejected(call, rejectWithMessage, textMessage); } call.reject(rejectWithMessage, textMessage); } }
这里先通知观察者来电拒接事件,比如CallAudioManager对该事件感兴趣,它的处理是停止播放来电铃声和来电等待声
com.android.server.telecom.CallAudioManager public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String message) { maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(call);}private void maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(Call call) { // Check to see if the call being answered/rejected is the only ringing call, since this // will be called before the connection service acknowledges the state change. if (mRingingCalls.size() == 0 || (mRingingCalls.size() == 1 && call == mRingingCalls.iterator().next())) { mRinger.stopRinging(); mRinger.stopCallWaiting(); } }
最后再调用前面传进来的call对象的reject方法
步骤7:Call的reject方法
com.android.server.telecom.Callpublic void reject(boolean rejectWithMessage, String textMessage) { Preconditions.checkNotNull(mConnectionService); // Check to verify that the call is still in the ringing state. A call can change states // between the time the user hits ‘reject‘ and Telecomm receives the command. if (isRinging("reject")) { // Ensure video state history tracks video state at time of rejection. mVideoStateHistory |= mVideoState; mConnectionService.reject(this, rejectWithMessage, textMessage); Log.event(this, Log.Events.REQUEST_REJECT); }}
这里的mConnectionService是ConnectionServiceWrapper类,是telecom与telephony通信的代理类
步骤8:ConnectionServiceWrapper的reject方法
com.android.server.telecom.ConnectionServiceWrappervoid reject(Call call, boolean rejectWithMessage, String message) { final String callId = mCallIdMapper.getCallId(call); if (callId != null && isServiceValid("reject")) { try { logOutgoing("reject %s", callId); if (rejectWithMessage && call.can( Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { mServiceInterface.rejectWithMessage(callId, message); } else { mServiceInterface.reject(callId); } } catch (RemoteException e) { } } }
这里mServiceInterface就是telephony提供给telecom调用的AIDL接口
步骤9:跨进程调用进入telephony进程,telephony进程实际服务类是TelephonyConnectionService继承于ConnectionService类在manifest声明如下:
<service android:singleUser="true" android:name="com.android.services.telephony.TelephonyConnectionService" android:label="@string/pstn_connection_service_label" android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" > <intent-filter> <action android:name="android.telecom.ConnectionService" /> </intent-filter></service>
而AIDL接口具体实现是其父类ConnectionService的mBinder成员变量
android.telecom.ConnectionService private final IBinder mBinder = new IConnectionService.Stub() { @Override public void reject(String callId) { mHandler.obtainMessage(MSG_REJECT, callId).sendToTarget(); }}
步骤10~13:发送MSG_REJECT消息到队列里处理
private void reject(String callId) { Log.d(this, "reject %s", callId); findConnectionForAction(callId, "reject").onReject(); } private Connection findConnectionForAction(String callId, String action) { if (mConnectionById.containsKey(callId)) { return mConnectionById.get(callId); } Log.w(this, "%s - Cannot find Connection %s", action, callId); return getNullConnection();}
根据callid找到对应的connection对象(android.telecom.Connection),调用onReject方法
步骤14:TelephonyConnection继承于connection
com.android.services.telephony.TelephonyConnectionpublic void onReject() { Log.v(this, "onReject"); if (isValidRingingCall()) { hangup(android.telephony.DisconnectCause.INCOMING_REJECTED); } super.onReject();}
protected void hangup(int telephonyDisconnectCode) { if (mOriginalConnection != null) { try { // Hanging up a ringing call requires that we invoke call.hangup() as opposed to // connection.hangup(). Without this change, the party originating the call will not // get sent to voicemail if the user opts to reject the call. if (isValidRingingCall()) { Call call = getCall(); if (call != null) { call.hangup(); } else { Log.w(this, "Attempting to hangup a connection without backing call."); } } else { // We still prefer to call connection.hangup() for non-ringing calls in order // to support hanging-up specific calls within a conference call. If we invoked // call.hangup() while in a conference, we would end up hanging up the entire // conference call instead of the specific connection. mOriginalConnection.hangup(); } } catch (CallStateException e) { Log.e(this, e, "Call to Connection.hangup failed with exception"); } } }
步骤15,16:这获取mOriginalConnection的call(com.android.internal.telephony.Call)对象,并调用hangup方法
protected Call getCall() { if (mOriginalConnection != null) { return mOriginalConnection.getCall(); } return null; }
Call是抽象类,具体子类是GsmCdmaCall
com.android.internal.telephony.GsmCdmaCallpublic void hangup() throws CallStateException { mOwner.hangup(this); }
mOwner是GsmCdmaCallTracker对象
步骤17:GsmCdmaCallTracker的hangup方法
com.android.internal.telephony.GsmCdmaCallTrackerpublic void hangup(GsmCdmaCall call) throws CallStateException { if (call.getConnections().size() == 0) { throw new CallStateException("no connections in call"); } if (call == mRingingCall) { if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); mCi.hangupWaitingOrBackground(obtainCompleteMessage()); } else if (call == mForegroundCall) { if (call.isDialingOrAlerting()) { if (Phone.DEBUG_PHONE) { log("(foregnd) hangup dialing or alerting..."); } hangup((GsmCdmaConnection)(call.getConnections().get(0))); } else if (isPhoneTypeGsm() && mRingingCall.isRinging()) { // Do not auto-answer ringing on CHUP, instead just end active calls log("hangup all conns in active/background call, without affecting ringing call"); hangupAllConnections(call); } else { hangupForegroundResumeBackground(); } } else if (call == mBackgroundCall) { if (mRingingCall.isRinging()) { if (Phone.DEBUG_PHONE) { log("hangup all conns in background call"); } hangupAllConnections(call); } else { hangupWaitingOrBackground(); } } else { throw new RuntimeException ("GsmCdmaCall " + call + "does not belong to GsmCdmaCallTracker " + this); } call.onHangupLocal(); mPhone.notifyPreciseCallStateChanged(); }
由于是ringcall,这里调用mCi.hangupWaitingOrBackground(obtainCompleteMessage());
mCi是CommandsInterface即RILJ接口,包装了一个EVENT_OPERATION_COMPLETE回调消息,发送给RIL
步骤18:RIL的hangupWaitingOrBackground方法
com.android.internal.telephony.RIL
hangupWaitingOrBackground (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); mEventLog.writeRilHangup(rr.mSerial, RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, -1); send(rr); }
给RIL层发送RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND消息
步骤19:mPhone.notifyPreciseCallStateChanged通知Phone状态监听事件
步骤20~24:收到RIL层的回应消息并处理,最后发送回调消息EVENT_OPERATION_COMPLETE给GsmCdmaCallTracker
步骤25:GsmCdmaCallTracker处理回调消息EVENT_OPERATION_COMPLETE
com.android.internal.telephony.GsmCdmaCallTracker private void operationComplete() { mPendingOperations--; if (DBG_POLL) log("operationComplete: pendingOperations=" + mPendingOperations + ", needsPoll=" + mNeedsPoll); if (mPendingOperations == 0 && mNeedsPoll) { mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); mCi.getCurrentCalls(mLastRelevantPoll); } else if (mPendingOperations < 0) { // this should never happen Rlog.e(LOG_TAG,"GsmCdmaCallTracker.pendingOperations < 0"); mPendingOperations = 0; } }
这里再次向RIL发送消息主动获取当前Call状态,包装的回调消息为EVENT_POLL_CALLS_RESULT
步骤26~32:RIL返回消息,GsmCdmaCallTracker接收EVENT_POLL_CALLS_RESULT消息并处理
protected synchronized void handlePollCalls(AsyncResult ar) { ................... for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) { GsmCdmaConnection conn = mDroppedDuringPoll.get(i); //CDMA boolean wasDisconnected = false; if (conn.isIncoming() && conn.getConnectTime() == 0) { // Missed or rejected call int cause; if (conn.mCause == DisconnectCause.LOCAL) { cause = DisconnectCause.INCOMING_REJECTED; } else { cause = DisconnectCause.INCOMING_MISSED; } if (Phone.DEBUG_PHONE) { log("missed/rejected call, conn.cause=" + conn.mCause); log("setting cause to " + cause); } mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(cause); wasDisconnected = true; } else if (conn.mCause == DisconnectCause.LOCAL || conn.mCause == DisconnectCause.INVALID_NUMBER) { mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause); wasDisconnected = true; } if (!isPhoneTypeGsm() && wasDisconnected && unknownConnectionAppeared && conn == newUnknownConnectionCdma) { unknownConnectionAppeared = false; newUnknownConnectionCdma = null; } ................... ................... updatePhoneState(); if (unknownConnectionAppeared) { if (isPhoneTypeGsm()) { for (Connection c : newUnknownConnectionsGsm) { log("Notify unknown for " + c); mPhone.notifyUnknownConnection(c); } } else { mPhone.notifyUnknownConnection(newUnknownConnectionCdma); } } if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged(); }}
这里设置DisconnectCause.INCOMING_REJECTED为连接断开的cause并调用GsmCdmaConnection的onDisconnect方法
步骤33:GsmCdmaConnection的onDisconnect方法
com.android.internal.telephony.GsmCdmaConnection public boolean onDisconnect(int cause) { boolean changed = false; mCause = cause; if (!mDisconnected) { doDisconnect(); if (DBG) Rlog.d(LOG_TAG, "onDisconnect: cause=" + cause); mOwner.getPhone().notifyDisconnect(this); if (mParent != null) { changed = mParent.connectionDisconnected(this); } mOrigConnection = null; } clearPostDialListeners(); releaseWakeLock(); return changed; }
doDisconnect方法设置断开时间以及通话时长
private void doDisconnect() { mIndex = -1; mDisconnectTime = System.currentTimeMillis(); mDuration = SystemClock.elapsedRealtime() - mConnectTimeReal; mDisconnected = true; clearPostDialListeners();}
最后通知注册者断开事件mOwner.getPhone().notifyDisconnect(this);
步骤34,36:通知phone状态变化事件给相关监听者
步骤35:GsmCdmaPhone通知通话断开事件
com.android.internal.telephony.GsmCdmaPhone public void notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); mNotifier.notifyDisconnectCause(cn.getDisconnectCause(), cn.getPreciseDisconnectCause());}
步骤37~40:TelephonyConnection注册了断开事件监听,接收并处理断开消息
com.android.services.telephony.TelephonyConnectionvoid setOriginalConnection(com.android.internal.telephony.Connection originalConnection) { Log.v(this, "new TelephonyConnection, originalConnection: " + originalConnection); ...... getPhone().registerForDisconnect(mHandler, MSG_DISCONNECT, null); ......}
void updateState() { if (mOriginalConnection == null) { return; } updateStateInternal(); updateStatusHints(); updateConnectionCapabilities(); updateConnectionProperties(); updateAddress(); updateMultiparty(); }
void updateStateInternal() { if (mOriginalConnection == null) { return; } Call.State newState; // If the state is overridden and the state of the original connection hasn‘t changed since, // then we continue in the overridden state, else we go to the original connection‘s state. if (mIsStateOverridden && mOriginalConnectionState == mOriginalConnection.getState()) { newState = mConnectionOverriddenState; } else { newState = mOriginalConnection.getState(); } Log.v(this, "Update state from %s to %s for %s", mConnectionState, newState, this); if (mConnectionState != newState) { mConnectionState = newState; switch (newState) { case IDLE: break; case ACTIVE: setActiveInternal(); break; case HOLDING: setOnHold(); break; case DIALING: case ALERTING: setDialing(); break; case INCOMING: case WAITING: setRinging(); break; case DISCONNECTED: setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause( mOriginalConnection.getDisconnectCause(), mOriginalConnection.getVendorDisconnectCause())); close(); break; case DISCONNECTING: break; } }}
通过DisconnectCauseUtil的toTelecomDisconnectCause方法生成DisconnectCause(android.telecom.DisconnectCause)对象
包含code, label, description, reason,toneToPlay信息
步骤41,42:通知外部监听者断开事件mNotifier.notifyDisconnectCause
步骤43:调用父类Connection的setDisconnected方法
public final void setDisconnected(DisconnectCause disconnectCause) { checkImmutable(); mDisconnectCause = disconnectCause; setState(STATE_DISCONNECTED); Log.d(this, "Disconnected with cause %s", disconnectCause); for (Listener l : mListeners) { l.onDisconnected(this, disconnectCause); } }
回调通知观察者ConnectionService注册了该事件,mConnectionListener接收处理
步骤44:mConnectionListener处理onDisconnected事件
android.telecom.ConnectionServiceprivate final Connection.Listener mConnectionListener = new Connection.Listener() { ...... @Override public void onDisconnected(Connection c, DisconnectCause disconnectCause) { String id = mIdByConnection.get(c); Log.d(this, "Adapter set disconnected %s", disconnectCause); mAdapter.setDisconnected(id, disconnectCause); }}
根据connection对象取出对应的callid
步骤45:TelephonyConnection的updateAddress方法更新connection信息
步骤46:ConnectionServiceAdapter的setDisconnected方法
android.telecom.ConnectionServiceAdapter void setDisconnected(String callId, DisconnectCause disconnectCause) { for (IConnectionServiceAdapter adapter : mAdapters) { try { adapter.setDisconnected(callId, disconnectCause); } catch (RemoteException e) { } }}
telecom在绑定TelephonyConnectionService的时候,会设置AIDL回调接口对象给telephony即ConnectionServiceWrapper的Adapter成员变量
步骤47:跨进程调用到telecom进程,ConnectionServiceWrapper的Adapter处理setDisconnected
com.android.server.telecom.ConnectionServiceWrapper private final class Adapter extends IConnectionServiceAdapter.Stub {...... @Override public void setDisconnected(String callId, DisconnectCause disconnectCause) { Log.startSession("CSW.sD"); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("setDisconnected %s %s", callId, disconnectCause); Call call = mCallIdMapper.getCall(callId); Log.d(this, "disconnect call %s %s", disconnectCause, call); if (call != null) { mCallsManager.markCallAsDisconnected(call, disconnectCause); } else { // Log.w(this, "setDisconnected, unknown call id: %s", args.arg1); } } } finally { Binder.restoreCallingIdentity(token); Log.endSession(); } }......}
根据callid取出Call(com.android.server.telecom.Call)对象,给CallsManager传递Call和disconnectCause
步骤48,49,50:CallsManager的markCallAsDisconnected方法
com.android.server.telecom.CallsManagervoid markCallAsDisconnected(Call call, DisconnectCause disconnectCause) { call.setDisconnectCause(disconnectCause); setCallState(call, CallState.DISCONNECTED, "disconnected set explicitly");}
给Call设置disconnectCause,同时设置callstate
private void setCallState(Call call, int newState, String tag) { if (call == null) { return; } int oldState = call.getState(); Log.i(this, "setCallState %s -> %s, call: %s", CallState.toString(oldState), CallState.toString(newState), call); if (newState != oldState) { // Unfortunately, in the telephony world the radio is king. So if the call notifies // us that the call is in a particular state, we allow it even if it doesn‘t make // sense (e.g., STATE_ACTIVE -> STATE_RINGING). // TODO: Consider putting a stop to the above and turning CallState // into a well-defined state machine. // TODO: Define expected state transitions here, and log when an // unexpected transition occurs. call.setState(newState, tag); maybeShowErrorDialogOnDisconnect(call); Trace.beginSection("onCallStateChanged"); // Only broadcast state change for calls that are being tracked. if (mCalls.contains(call)) { updateCallsManagerState(); for (CallsManagerListener listener : mListeners) { if (Log.SYSTRACE_DEBUG) { Trace.beginSection(listener.getClass().toString() + " onCallStateChanged"); } listener.onCallStateChanged(call, oldState, newState); if (Log.SYSTRACE_DEBUG) { Trace.endSection(); } } } Trace.endSection(); }}
最后回调onCallStateChanged方法通知监听者,这里监听call状态变化的对象有很多,我们看下InCallController的处理
步骤51,52:InCallController的onCallStateChanged方法
com.android.server.telecom.InCallController @Override public void onCallStateChanged(Call call, int oldState, int newState) { updateCall(call); }
private void updateCall(Call call, boolean videoProviderChanged) { if (!mInCallServices.isEmpty()) { ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall( call, videoProviderChanged /* includeVideoProvider */, mCallsManager.getPhoneAccountRegistrar()); Log.i(this, "Sending updateCall %s ==> %s", call, parcelableCall); List<ComponentName> componentsUpdated = new ArrayList<>(); for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) { ComponentName componentName = entry.getKey(); IInCallService inCallService = entry.getValue(); componentsUpdated.add(componentName); try { inCallService.updateCall(parcelableCall); } catch (RemoteException ignored) { } } Log.i(this, "Components updated: %s", componentsUpdated); } }}
根据call信息生成ParcelableCall对象,给incallservice传递ParcelableCall
步骤53,54:InCallService的updateCall方法
android.telecom.InCallService @Override public void updateCall(ParcelableCall call) { mHandler.obtainMessage(MSG_UPDATE_CALL, call).sendToTarget(); }
private final Handler mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { ...... case MSG_UPDATE_CALL: mPhone.internalUpdateCall((ParcelableCall) msg.obj); break;}
步骤55:Phone的internalUpdateCall方法
android.telecom.Phone final void internalUpdateCall(ParcelableCall parcelableCall) { Call call = mCallByTelecomCallId.get(parcelableCall.getId()); if (call != null) { checkCallTree(parcelableCall); call.internalUpdate(parcelableCall, mCallByTelecomCallId); }}
这里的Phone对象只是一个管理类,保存call列表信息和与telecom通信的AIDL接口对象,通过callid取出Call(android.telecom.Call)对象
步骤56:Call的internalUpdate方法
android.telecom.Callfinal void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { Details details = Details.createFromParcelableCall(parcelableCall); ...... ...... // Now we fire updates, ensuring that any client who listens to any of these notifications // gets the most up-to-date state. if (stateChanged) { fireStateChanged(mState); } if (detailsChanged) { fireDetailsChanged(mDetails); } if (cannedTextResponsesChanged) { fireCannedTextResponsesLoaded(mCannedTextResponses); } if (videoCallChanged) { fireVideoCallChanged(mVideoCallImpl); } if (parentChanged) { fireParentChanged(getParent()); } if (childrenChanged) { fireChildrenChanged(getChildren()); } // If we have transitioned to DISCONNECTED, that means we need to notify clients and // remove ourselves from the Phone. Note that we do this after completing all state updates // so a client can cleanly transition all their UI to the state appropriate for a // DISCONNECTED Call while still relying on the existence of that Call in the Phone‘s list. if (mState == STATE_DISCONNECTED) { fireCallDestroyed(); }}
步骤57:转化ParcelableCall 信息为Detail信息,判断call状态是否有变化,有则进入fireStateChanged
private void fireStateChanged(final int newState) { for (CallbackRecord<Callback> record : mCallbackRecords) { final Call call = this; final Callback callback = record.getCallback(); record.getHandler().post(new Runnable() { @Override public void run() { callback.onStateChanged(call, newState); } }); }}
步骤58:这里遍历Call(android.telecom.Call)对象里的回调监听者
private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
也就是每次InCallPresenter添加Call(android.telecom.Call)时添加的注册回调事件
com.android.incallui.InCallPresenterpublic void onCallAdded(final android.telecom.Call call) { if (shouldAttemptBlocking(call)) { maybeBlockCall(call); } else { mCallList.onCallAdded(call); } // Since a call has been added we are no longer waiting for Telecom to send us a call. setBoundAndWaitingForOutgoingCall(false, null); call.registerCallback(mCallCallback); }
这里有两个地方注册了事件回调,一个是在CallList的onCallAdd方法里转化Call(android.telecom.Call)创建了Call(com.android.incallui.Call)对象时注册的
com.android.incallui.CallList public void onCallAdded(final android.telecom.Call telecomCall) { Trace.beginSection("onCallAdded"); final Call call = new Call(telecomCall); Log.d(this, "onCallAdded: callState=" + call.getState()); if (call.getState() == Call.State.INCOMING || call.getState() == Call.State.CALL_WAITING) { onIncoming(call, call.getCannedSmsResponses()); } else { onUpdate(call); } call.logCallInitiationType(); Trace.endSection(); }
com.android.incallui.Callpublic Call(android.telecom.Call telecomCall) { mTelecomCall = telecomCall; mId = ID_PREFIX + Integer.toString(sIdCounter++); updateFromTelecomCall(); mTelecomCall.registerCallback(mTelecomCallCallback); mTimeAddedMs = System.currentTimeMillis(); }
还有就是InCallPresenter的成员变量mCallCallback的注册
这里onStateChange只有Call(com.android.incallui.Call)的成员变量mTelecomCallCallback有处理
com.android.incallui.Callprivate final android.telecom.Call.Callback mTelecomCallCallback = new android.telecom.Call.Callback() { ...... ...... @Override public void onStateChanged(android.telecom.Call call, int newState) { Log.d(this, "TelecomCallCallback onStateChanged call=" + call + " newState=" + newState); update(); } @Override public void onCallDestroyed(android.telecom.Call call) { Log.d(this, "TelecomCallCallback onStateChanged call=" + call); call.unregisterCallback(this); } };
步骤59:进入Call(com.android.incallui.Call)的update方法
private void update() { Trace.beginSection("Update"); int oldState = getState(); updateFromTelecomCall(); if (oldState != getState() && getState() == Call.State.DISCONNECTED) { CallList.getInstance().onDisconnect(this); } else { CallList.getInstance().onUpdate(this); } Trace.endSection();}
步骤61~69:由于是DISCONNECTED状态,进入CallList的onDisconnect,最后回调到InCallPresenter的onDisconnect方法
com.android.incallui.InCallPresenter @Override public void onDisconnect(Call call) { maybeShowErrorDialogOnDisconnect(call); // We need to do the run the same code as onCallListChange. onCallListChange(mCallList); if (isActivityStarted()) { mInCallActivity.dismissKeyguard(false); } if (call.isEmergencyCall()) { FilteredNumbersUtil.recordLastEmergencyCallTime(mContext); }}
InCallPresenter内部更新call状态事件并触发回调通知,细节再次就不一一罗列了
回调步骤57在执行完fireStateChanged方法后,后续还有fireDetailsChanged等事件(如果有变化的话),这里我们关注下fireCallDestroyed
android.telecom.Callprivate void fireCallDestroyed() { final Call call = this; if (mCallbackRecords.isEmpty()) { // No callbacks registered, remove the call from Phone‘s record. mPhone.internalRemoveCall(call); } for (final CallbackRecord<Callback> record : mCallbackRecords) { final Callback callback = record.getCallback(); record.getHandler().post(new Runnable() { @Override public void run() { boolean isFinalRemoval = false; RuntimeException toThrow = null; try { callback.onCallDestroyed(call); } catch (RuntimeException e) { toThrow = e; } synchronized(Call.this) { mCallbackRecords.remove(record); if (mCallbackRecords.isEmpty()) { isFinalRemoval = true; } } if (isFinalRemoval) { mPhone.internalRemoveCall(call); } if (toThrow != null) { throw toThrow; } } }); } }
这里 callback.onCallDestroyed(call);通知call销毁事件
步骤60:反注册Call(android.telecom.Call )的监听事件
com.android.incallui.Call @Override public void onCallDestroyed(android.telecom.Call call) { Log.d(this, "TelecomCallCallback onStateChanged call=" + call); call.unregisterCallback(this); }
步骤63,64:mPhone.internalRemoveCall(call); 把Call(android.telecom.Call)对象从列表中移除,通知onCallRemoved事件
android.telecom.Phonefinal void internalRemoveCall(Call call) { mCallByTelecomCallId.remove(call.internalGetCallId()); mCalls.remove(call); InCallService.VideoCall videoCall = call.getVideoCall(); if (videoCall != null) { videoCall.destroy(); } fireCallRemoved(call); }
private void fireCallRemoved(Call call) { for (Listener listener : mListeners) { listener.onCallRemoved(this, call); } }
步骤70,71:InCallService处理onCallRemoved事件
com.android.incallui.InCallServiceImpl@Override public void onCallAdded(Call call) { InCallPresenter.getInstance().onCallAdded(call); }
步骤72:进入InCallPresenter的onCallRemoved方法
com.android.incallui.InCallPresenterpublic void onCallRemoved(android.telecom.Call call) { mCallList.onCallRemoved(call); call.unregisterCallback(mCallCallback); }
步骤73~78:CallList的onCallRemoved方法:
com.android.incallui.CallListpublic void onCallRemoved(android.telecom.Call telecomCall) { if (mCallByTelecomCall.containsKey(telecomCall)) { Call call = mCallByTelecomCall.get(telecomCall); Logger.logCall(call); if (updateCallInMap(call)) { Log.w(this, "Removing call not previously disconnected " + call.getId()); } updateCallTextMap(call, null); }}
CallList内部更新状态最终回调InCallPresenter的onCallListChange方法
com.android.incallui.InCallPresenterpublic void onCallListChange(CallList callList) { if (mInCallActivity != null && mInCallActivity.getCallCardFragment() != null && mInCallActivity.getCallCardFragment().isAnimating()) { mAwaitingCallListUpdate = true; return; } if (callList == null) { return; } mAwaitingCallListUpdate = false; InCallState newState = getPotentialStateFromCallList(callList); InCallState oldState = mInCallState; Log.d(this, "onCallListChange oldState= " + oldState + " newState=" + newState); newState = startOrFinishUi(newState); Log.d(this, "onCallListChange newState changed to " + newState); // Set the new state before announcing it to the world Log.i(this, "Phone switching state: " + oldState + " -> " + newState); mInCallState = newState; // notify listeners of new state for (InCallStateListener listener : mListeners) { Log.d(this, "Notify " + listener + " of state " + mInCallState.toString()); listener.onStateChange(oldState, mInCallState, callList); } if (isActivityStarted()) { final boolean hasCall = callList.getActiveOrBackgroundCall() != null || callList.getOutgoingCall() != null; mInCallActivity.dismissKeyguard(hasCall); } }
步骤79,80,81:InCallPresenter处理disconnected事件并触发相关回调更新界面等
至此,一个来电的整体流程都分析完了,大致流程如下:
InCallUI →TeleComService→TeleponyService→TelephonyFramework →RIL→
RIL→TelephonyFramework →TeleponyService→TeleComFramework→TeleComService→TeleComFramework-->InCallUI
Android7.0 Phone应用源码分析(三) phone拒接流程分析