首页 > 代码库 > 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拒接流程分析