Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 6.0 MT流程

Android 6.0 MT流程

編輯:關於Android編程

一. 列表內容

這段負責通話模塊的開發,研究了一下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-Java在本質上就是一個RIL代理,起到一個轉發的作用,是Android 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);

 @Override
    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);
...
 @Override
    public void
//響應處理
    handleMessage (Message msg) {
...
 case EVENT_CALL_STATE_CHANGE: //MT第一次
//調用父類CallTracker查詢Call List方法
     pollCallsWhenSafe();
     break;

4、pollCallsWhenSafe()方法在CallTracker.java中實現

protected void pollCallsWhenSafe() {

        mNeedsPoll = true;

        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
    5、     //RIL.java中的getCurrentCalls方法  
            mCi.getCurrentCalls(mLastRelevantPoll);
        }
    }

回到RIL.java getCurrentCalls 將RIL_REQUEST_GET_CURRENT_CALLS 消息封裝成RILRequest
類型並發送。

@Override
    public void getCurrentCalls (Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
        send(rr);
    }

RIL.java 有三處接收處理RIL_REQUEST_GET_CURRENT_CALLS消息,真正的邏輯處理在processSolicited方法

private RILRequest processSolicited (Parcel p) {
...
case RIL_REQUEST_GET_CURRENT_CALLS: ret =  responseCallList(p); break;
...
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”

@Override
    public void handleMessage (Message msg) {
        ...
        case EVENT_POLL_CALLS_RESULT:
                ar = (AsyncResult)msg.obj;
                if (msg == mLastRelevantPoll) {
                    mNeedsPoll = false;
                    mLastRelevantPoll = null;
         7、        handlePollCalls((AsyncResult)msg.obj);
                }
            break;

8、handlePollCalls方法根據RIL發出的Call List對象判斷Call的狀態,並發出不同的通知,

1) 新來電的通知是: phone.notifyNewRingingConnection;
另外兩個是
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)
            return;
        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 < s ; i++) {
            Registrant  r = (Registrant) registrants.get(i);
            r.internalNotifyRegistrant(result, exception);
       }
    }
    /*package*/ void internalNotifyRegistrant (Object result, Throwable exception)
    {
        Handler h = getHandler();

        if (h == null) {
            clear();
        } else {
            Message msg = Message.obtain();

            msg.what = what;

            msg.obj = new AsyncResult(userObj, result, exception);

            h.sendMessage(msg);
        }
    }   

注冊為觀察者的方法為:

// Inherited documentation suffices.
    @Override
    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.517962  1596  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 = newPhone;
                //調用registerForNewRingingConnection方法
                mPhoneBase.registerForNewRingingConnection(
                        mHandler, EVENT_NEW_RINGING_CONNECTION, null);
                mPhoneBase.registerForCallWaiting(
                        mHandler, EVENT_CDMA_CALL_WAITING, null);
                mPhoneBase.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION,
                        null);
            }
        }
    }

11、handle 處理EVENT_NEW_RINGING_CONNECTION消息

private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
        ...
            case EVENT_NEW_RINGING_CONNECTION:
                    handleNewRingingConnection((AsyncResult) msg.obj);
                    break;

12、從之前的log看: 由handleNewRingingConnection方法,處理新的來電連接。

    private void handleNewRingingConnection(AsyncResult asyncResult) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
        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 = null;
        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) {
        try {
            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
         */
        @Override
        public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
            synchronized (mLock) {
                    long token = Binder.clearCallingIdentity();
                    try {
                        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(
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                handle,
                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();
            } else {
                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);
                return;
            }
            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 isBound;
                if (mUserHandle != null) {
                    isBound = mContext.bindServiceAsUser(serviceIntent, connection, bindingFlags,
                            mUserHandle);
                } else {
                    isBound = mContext.bindService(serviceIntent, connection, bindingFlags);
                }
                if (!isBound) {
                    handleFailedConnection();
                    return;
                }
            } else {
                Log.d(ServiceBinder.this, "Service is already bound.");
                Preconditions.checkNotNull(mBinder);
                handleSuccessfulConnection();
            }
        }

26、上面的執行完之後,順序執行到onServiceConnected

onServiceConnected

 private final class ServiceBinderConnection implements ServiceConnection {
        @Override
        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();
                return;
            }
            mServiceConnection = this;
            setBinder(binder);
            handleSuccessfulConnection();
        }

27、

    private void handleSuccessfulConnection() {
        for (BindCallback callback : mCallbacks) {
            callback.onSuccess();
        }
        mCallbacks.clear();
    }

28、回調上面的onSuccess() 執行mServiceInterface.createConnectioncreateConnection的具體實現在ConnectionService.java (frameworks\base\telecomm\java\android\telecom)

作用:一個提供電話連接到Android設備上運行的進程。

        @Override
        public void createConnection(
                PhoneAccountHandle connectionManagerPhoneAccount,
                String id,
                ConnectionRequest request,
                boolean isIncoming,
                boolean isUnknown) {
            //chengzhi
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = connectionManagerPhoneAccount;
            args.arg2 = id;
            args.arg3 = request;
            args.argi1 = isIncoming ? 1 : 0;
            args.argi2 = isUnknown ? 1 : 0;
29、        mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
        }

30、

case MSG_CREATE_CONNECTION: {
                         createConnection(
                                    connectionManagerPhoneAccount,
                                    id,
                                    request,
                                    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) {
            try {
                //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 {

        @Override
        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() {
        @Override
        public void handleCreateConnectionComplete(
                String id,
                ConnectionRequest request,
                ParcelableConnection connection) {
            SomeArgs args = SomeArgs.obtain();
            args.arg1 = id;
            args.arg2 = request;
            args.arg3 = connection;
            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.obj;
                    try {
                        mDelegate.handleCreateConnectionComplete(
                                (String) args.arg1,
                                (ConnectionRequest) args.arg2,
                                (ParcelableConnection) args.arg3);
                    } finally {
                        args.recycle();
                    }
                    break;
                }

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
            // failure to connect; we handle all failures uniformly
            removeCall(callId, connection.getDisconnectCause());
        } else {
            // 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()

@Override
    public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        Log.v(this, "handleCreateConnectionSuccessful %s", connection);
        mCreateConnectionProcessor = null;
        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 = true;

            // 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()));
        } else {
            for (Listener l : mListeners) {
                l.onSuccessfulOutgoingCall(this,
                        getStateFromConnectionState(connection.getState()));
            }
        }
    }

37、 Runnable mDirectToVoicemailRunnable

    private final Runnable mDirectToVoicemailRunnable = new Runnable() {
        @Override
        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);
            } else {
                // 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 = false;
        }
    }

39. package/services/Telecomm/src/com/android/server/telecom/CallsManager.java

39.1@Override onSuccessfulIncomingCall if 判斷後 addCall()

public final class CallsManager extends Call.ListenerBase {
...
    @Override
    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);
        } else {
            incomingCall.mIsActiveSub = true;
            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 –>

    @Override
    public void onCallAdded(Call call) {
        if (!isBoundToServices()) {
            bindToServices(call);
        } else {
            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 */);
                try {
                    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);
        }

42 、

    private void onConnected(ComponentName componentName, IBinder service) {
        addCall(call);
    }

43. framworks/base/telecomm/java/android/telecom/InCallService.java

作用:這個服務可以被任何希望提供管理電話的用戶界面的應用實現,
當那個服務存在一個電話telecom就去綁定這個服務並用它去通知任何活動狀態和最近斷開的呼叫的被調用的應用
@Override
addCall()

    /** Manages the binder calls so that the implementor does not need to deal with it. */
    private final class InCallServiceBinder extends IInCallService.Stub {
        @Override
        public void setInCallAdapter(IInCallAdapter inCallAdapter) {
            mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
        }

        @Override
        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()) {
        @Override
        public void handleMessage(Message msg) {
            if (mPhone == null && msg.what != MSG_SET_IN_CALL_ADAPTER) {
                return;
            }

            switch (msg.what) {
                case MSG_SET_IN_CALL_ADAPTER:
                    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
                    onPhoneCreated(mPhone);
                    break;
                case MSG_ADD_CALL:
                    mPhone.internalAddCall((ParcelableCall) msg.obj);
                    break;

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
@Override
onCallAdded

    /**
     * Static singleton accessor method.
     */
    public static CallList getInstance() {
        return sInstance;
    }

    private Phone.Listener mPhoneListener = new Phone.Listener() {
        @Override
        public void onCallAdded(Phone phone, android.telecom.Call telecommCall) {
            Call call = new Call(telecommCall);
            if (call.getState() == Call.State.INCOMING) {
                onIncoming(call, call.getCannedSmsResponses());
            } else {
                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
     */
    @Override
    public void onIncomingCall(Call call) {
        InCallState newState = startOrFinishUi(InCallState.INCOMING);
        InCallState oldState = mInCallState;

        Log.i(this, "Phone switching state: " + oldState + " -> " + newState);
        mInCallState = newState;

        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 ,  擴展了很多好用的功能。具體請參考Github.

表格

Markdown Extra 表格語法:

項目 價格 Computer $1600 Phone $12 Pipe $1

可以使用冒號來定義對齊方式:

項目 價格 數量 Computer 1600 元 5 Phone 12 元 12 Pipe 1 元 234

定義列表

Markdown Extra 定義列表語法: 項目1 項目2 定義 A 定義 B 項目3 定義 C

定義 D

定義D內容

代碼塊

代碼塊語法遵循標准markdown代碼,例如:

@requires_authorization
def somefunc(param1='', param2=0):
    '''A docstring'''
    if param1 > param2: # interesting
        print 'Greater'
    return (param2 - param1 + 1) or None
class SomeClass:
    pass
>>> message = '''interpreter
... prompt'''

腳注

生成一個腳注。

數學公式

使用MathJax渲染LaTex 數學公式.

行內公式,數學公式為:Γ(n)=(n?1)!?n∈N。 塊級公式: x=?b±b2?4ac???????√2a

 

UML 圖:

可以渲染序列圖:

Created with Rapha?l 2.1.0張三張三李四李四嘿,小四兒, 寫博客了沒?李四愣了一下,說:忙得吐血,哪有時間寫。

或者流程圖:

Created with Rapha?l 2.1.0開始我的操作確認?結束yesno

離線寫博客

即使用戶在沒有網絡的情況下,也可以通過本編輯器離線寫博客(直接在曾經使用過的浏覽器中輸入write.blog.csdn.net/mdeditor即可。Markdown編輯器使用浏覽器離線存儲將內容保存在本地。

用戶寫博客的過程中,內容實時保存在浏覽器緩存中,在用戶關閉浏覽器或者其它異常情況下,內容不會丟失。用戶再次打開浏覽器時,會顯示上次用戶正在編輯的沒有發表的內容。

博客發表後,本地緩存將被刪除。 

用戶可以選擇 把正在寫的博客保存到服務器草稿箱,即使換浏覽器或者清除緩存,內容也不會丟失。

注意:雖然浏覽器存儲大部分時候都比較可靠,但為了您的數據安全,在聯網後,請務必及時發表或者保存到服務器草稿箱

浏覽器兼容

目前,本編輯器對Chrome浏覽器支持最為完整。建議大家使用較新版本的Chrome。 IE9以下不支持 IE9,10,11存在以下問題
不支持離線功能 IE9不支持文件導入導出 IE10不支持拖拽文件導入


  • 這裡是 腳注內容. ?
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved