Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android7.0 Phone應用源碼分析(二) phone來電流程分析,android7.0phone

Android7.0 Phone應用源碼分析(二) phone來電流程分析,android7.0phone

編輯:關於android開發

Android7.0 Phone應用源碼分析(二) phone來電流程分析,android7.0phone


接上篇博文:Android7.0 Phone應用源碼分析(一) phone撥號流程分析

今天我們再來分析下Android7.0 的phone的來電流程

1.1TelephonyFramework

當有來電通知時,首先接收到消息的是Modem層,然後Medoem再上傳給RIL層,RIL進程通過sokcet將消息發送給RILJ(framework層的RIL),同樣進入RILJ的processResponse方法,根據上一章節去電流程的分析得知,來電屬於UnSolicited消息,事件ID是

RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED,看看RILJ裡的處理

com.android.internal.telephony.RIL
processUnsolicited (Parcel p, int type) {
        ………………………………
   switch(response) {
        case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret =  responseVoid(p); 
        break;
        ………………………………
   }
        ………………………………
  switch(response) {
       case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
         if (RILJ_LOGD) unsljLog(response);
             mCallStateRegistrants .notifyRegistrants(new AsyncResult(null, null, null));
         break;
         ………………………………
    }
         ………………………………
}

mCallStateRegistrants是RegistrantList實例,這裡用到了觀察者模式,mCallStateRegistrants將call狀態的變化通知給了所有感興趣的注冊者,BaseCommands提供了相關注冊接口

com.android.internal.telephony. registerForCallStateChanged
 @Override
    public void registerForCallStateChanged(Handler h, int what, Object obj) {
        Registrant r = new Registrant (h, what, obj);

        mCallStateRegistrants.add(r);
    }
}

最後找到GsmCdmaCallTracker在創建的時候注冊了該事件

com.android.internal.telephony. GsmCdmaCallTracker
public GsmCdmaCallTracker (GsmCdmaPhone phone) {
        this.mPhone = phone;
        mCi = phone.mCi;
        mCi.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
        mCi.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
        mCi.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
        ...... ......

}

收到EVENT_CALL_STATE_CHANGE消息後進入pollCallsWhenSafe方法

protected void pollCallsWhenSafe() {
        mNeedsPoll = true;

        if (checkNoOperationsPending()) {
            mLastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
            mCi.getCurrentCalls(mLastRelevantPoll);
        }}
}

這裡的處理流程跟之前撥號類似,同樣是通過RILJ獲取當前call狀態,收到回應後進入handlePollCalls方法

protected synchronized void handlePollCalls(AsyncResult ar) {
      ………………………………
     if (newRinging != null) {          // 新來電通知
        mPhone.notifyNewRingingConnection(newRinging);
     }
       ………………………………
    updatePhoneState();                // 更新phone狀態
       ………………………………
  if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected)           {
      mPhone.notifyPreciseCallStateChanged();  // 發出call狀態變化通知

   }
}

新來電進入phone的notifyNewRingingConnection的方法

com.android.internal.telephony.Phone 
public void notifyNewRingingConnectionP(Connection cn) {
   if (!mIsVoiceCapable)
         return;
    AsyncResult ar = new AsyncResult(null, cn, null);
   mNewRingingConnectionRegistrants.notifyRegistrants(ar);}
}

又是一個觀察者模式,最後找到是注冊了該事件的監聽對象PstnIncomingCallNotifier

1.2TelephonyService

com.android.services.telephony. PstnIncomingCallNotifier
private void registerForNotifications() {
  if (mPhone != null) {
         Log.i(this, "Registering: %s", mPhone);
         mPhone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
         mPhone.registerForCallWaiting(mHandler, EVENT_CDMA_CALL_WAITING, null);
         mPhone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
        }
}

Handler處理消息進入handleNewRingingConnection方法

private void handleNewRingingConnection(AsyncResult asyncResult) {
        Log.d(this, "handleNewRingingConnection");
        Connection connection = (Connection) asyncResult.result;
        if (connection != null) {
            Call call = connection.getCall();

            // Final verification of the ringing state before sending the intent to Telecom.
            if (call != null && call.getState().isRinging()) {
                sendIncomingCallIntent(connection);
            }
        }
 }

獲取到call對象以後,最後進入sendIncomingCallIntent

private void sendIncomingCallIntent(Connection connection) {    
       ………………………………
        PhoneAccountHandle handle = findCorrectPhoneAccountHandle();
        if (handle == null) {
            try {
                connection.hangup();
            } catch (CallStateException e) {
                // connection already disconnected. Do nothing
            }
        } else {
           TelecomManager.from(mPhone.getContext()).addNewIncomingCall(handle, extras);
        }
  }

通過aidl接口調用telecomservice的的addNewIncomingCall方法

1.3 TelecomService

TelecomServiceImpl的成員變量mBinderImpl是具體實現類

com.android.server.telecom.TelecomServiceImpl
private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub(){
public void addNewIncomingCall(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
   ………………………………
   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) { 
           extras.setDefusable(true);
           intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
    }
    mCallIntentProcessorAdapter.processIncomingCallIntent(mCallsManager, intent);

}
    ………………………………

}

這裡調用到的是CallIntentProcessor 的processIncomingCallIntent方法

com.android.server.telecom. CallIntentProcessor
static void processIncomingCallIntent(CallsManager callsManager, Intent intent) {
       ………………………………
        Log.d(CallIntentProcessor.class,
                "Processing incoming call from connection service [%s]",
                phoneAccountHandle.getComponentName());
        callsManager.processIncomingCallIntent(phoneAccountHandle, clientExtras);
}

進入callsmanager的processIncomingCallIntent方法

void processIncomingCallIntent(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
       ………………………………
        Call call = new Call(
                getNextCallId(),
                mContext,
                this,
                mLock,
                mConnectionServiceRepository,
                mContactsAsyncHelper,
                mCallerInfoAsyncQueryFactory,
                handle,
                null /* gatewayInfo */,
                null /* connectionManagerPhoneAccount */,
                phoneAccountHandle,
                Call.CALL_DIRECTION_INCOMING /* callDirection */,
                false /* forceAttachToExistingConnection */,
                false /* isConference */
        );
        ………………………………
        call.addListener(this);
        call.startCreateConnection(mPhoneAccountRegistrar);
    }

走到這一步,跟之前分析的撥號流程一樣,創建了一個call對象,然後調用

startCreateConnection創建連接,根據之前撥號的流程分析最後會進入 ConnectionService的createConnection方法

1.4 TelecommFramework

再把實現代碼貼一遍:

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(
                callId,
                request,
                new ParcelableConnection(
                        request.getAccountHandle(),
                        connection.getState(),
                        connection.getConnectionCapabilities(),
                        connection.getConnectionProperties(),
                        connection.getAddress(),
                        connection.getAddressPresentation(),
                        connection.getCallerDisplayName(),
                        connection.getCallerDisplayNamePresentation(),
                        connection.getVideoProvider() == null ?
                                null : connection.getVideoProvider().getInterface(),
                        connection.getVideoState(),
                        connection.isRingbackRequested(),
                        connection.getAudioModeIsVoip(),
                        connection.getConnectTimeMillis(),
                        connection.getStatusHints(),
                        connection.getDisconnectCause(),
                        createIdList(connection.getConferenceables()),
                        connection.getExtras(),
                        connection.getUserData()));//MOTO Calling Code - IKPIM-1774 (ftr 33860)
        if (isUnknown) {
            triggerConferenceRecalculate();
        }
}

這裡由於是來電,所以調用onCreateIncomingConnection方法,該方法同樣返回null,所以具體是由其子類實現的,也就是TelephonyConnectionService

public Connection onCreateIncomingConnection(
            PhoneAccountHandle connectionManagerPhoneAccount,
            ConnectionRequest request) {
       
    
        Connection connection =  createConnectionFor(phone, originalConnection, false /* isOutgoing */,
                        request.getAccountHandle(), request.getTelecomCallId(),
                        request.getAddress());
        if (connection == null) {
            return Connection.createCanceledConnection();
        } else {
            return connection;
        }
  }

最後根據GMS或是CDMA返回對應Connection對象,最後進入ConnectionServiceAdapter處理

android.telecom. ConnectionServiceAdapter
  void handleCreateConnectionComplete(
            String id,
            ConnectionRequest request,
            ParcelableConnection connection) {
        for (IConnectionServiceAdapter adapter : mAdapters) {
            try {
                adapter.handleCreateConnectionComplete(id, request, connection);
            } catch (RemoteException e) {
            }
        }
}

這裡的adapter實際上就是ConnectionServiceWrapper的內部類Adapter,需要注意的是之前撥號的時候創建完connection並呼出之後,後續也會走到這個流程裡

public void handleCreateConnectionComplete(String callId, ConnectionRequest request,
                ParcelableConnection connection) {
            Log.startSession("CSW.hCCC");
            long token = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    logIncoming("handleCreateConnectionComplete %s", callId);
                    ConnectionServiceWrapper.this
                       handleCreateConnectionComplete(callId, request, connection);
                }
            } finally {
                Binder.restoreCallingIdentity(token);
                Log.endSession();
            }
}

最後進入handleCreateConnectionComplete方法

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);
            }
        }
}

這裡的mPendingResponses是map容器

private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();

ConnectionServiceWrapper在調用createConnection的時候會往該容器裡添加對象,也就是CreateConnectionProcessor對象

public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
        if (mCallResponse == null) {
            // Nobody is listening for this connection attempt any longer; ask the responsible
            // ConnectionService to tear down any resources associated with the call
            mService.abort(mCall);
        } else {
            // Success -- share the good news and remember that we are no longer interested
            // in hearing about any more attempts
            mCallResponse.handleCreateConnectionSuccess(idMapper, connection);
            mCallResponse = null;
            // If there's a timeout running then don't clear it. The timeout can be triggered
            // after the call has successfully been created but before it has become active.
        }
}

這個mCallResponse是CreateConnectionProcessor創建的時候引入的,也就是call對象

com.android.server.telecom.Call
   public void handleCreateConnectionSuccess(
            CallIdMapper idMapper,
            ParcelableConnection connection) {
     
        switch (mCallDirection) {
            case CALL_DIRECTION_INCOMING:
      
                for (Listener l : mListeners) {
                    l.onSuccessfulIncomingCall(this);
                }
                break;
            case CALL_DIRECTION_OUTGOING:
                for (Listener l : mListeners) {
                    l.onSuccessfulOutgoingCall(this,
                            getStateFromConnectionState(connection.getState()));
                }
                break;
            case CALL_DIRECTION_UNKNOWN:
                for (Listener l : mListeners) {
                      l.onSuccessfulUnknownCall(this, getStateFromConnectionState(connection .getState()));
                }
                break;
        }
    }

這裡根據是來電還是去電類型,執行相應回調,監聽者會收到通知,來電事件則觸發onSuccessfulIncomingCall的回調

1.5 TelecommService

前面提到CallsManager在執行processIncomingCallIntent方法時候會創建call,之後就會給call添加監聽,所以最後會回調到CallsManager類

public void onSuccessfulIncomingCall(Call incomingCall) {
        Log.d(this, "onSuccessfulIncomingCall");
        List<IncomingCallFilter.CallFilter> filters = new ArrayList<>();
        filters.add(new DirectToVoicemailCallFilter(mCallerInfoLookupHelper));
        filters.add(new 
AsyncBlockCheckFilter
(mContext, new BlockCheckerAdapter()));
        filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar,
                mDefaultDialerManagerAdapter,
                new ParcelableCallUtils.Converter(), mLock));
        new 
IncomingCallFilter
(mContext, this, incomingCall, mLock,
                mTimeoutsAdapter, filters).performFiltering();
}

這裡用到了一個迭代器模式,一個來電操作觸發這三個對象的處理:

DirectToVoicemailCallFilter,AsyncBlockCheckFilter,CallScreeningServiceFilter

生成一個IncomingCallFilter對象,調用performFiltering方法

com.android.server.telecom.callfiltering. IncomingCallFilter
 public void performFiltering() {
        Log.event(mCall, Log.Events.FILTERING_INITIATED);
        for (CallFilter filter : mFilters) {
            filter.startFilterLookup(mCall, this);
        }
        mHandler.postDelayed(new Runnable("ICF.pFTO") { // performFiltering time-out
            @Override
            public void loggedRun() {
                // synchronized to prevent a race on mResult and to enter into Telecom.
                synchronized (mTelecomLock) {
                    if (mIsPending) {
                        Log.i(IncomingCallFilter.this, "Call filtering has timed out.");
                        Log.event(mCall, Log.Events.FILTERING_TIMED_OUT);
                        mListener.onCallFilteringComplete(mCall, mResult);
                        mIsPending = false;
                    }
                }
            }
   }.prepare(), mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));
}

他們依次執行startFilterLookup異步查詢方法,通過回調方法並將結果CallFilteringResult傳回onCallFilteringComplete將CallFilteringResult對象傳遞回來

public class CallFilteringResult {

    public boolean shouldAllowCall;          // 是否允許通話
    public boolean shouldReject;            // 是否拒接
    public boolean shouldAddToCallLog;     // 是否添加至通話記
    public boolean shouldShowNotification; // 是否顯示通知欄消息
   ………………………………
   ………………………………
}

public void onCallFilteringComplete(Call call, CallFilteringResult result) {
        synchronized (mTelecomLock) { // synchronizing to prevent race on mResult
            mNumPendingFilters--;
            mResult = result.combine(mResult);
            if (mNumPendingFilters == 0) {
                mHandler.post(new Runnable("ICF.oCFC") {
                    @Override
                    public void loggedRun() {
                        // synchronized to enter into Telecom.
                        synchronized (mTelecomLock) {
                            if (mIsPending) {
                                mListener.onCallFilteringComplete(mCall, mResult);
                                mIsPending = false;
                            }
                        }
                    }
                }.prepare());
            }
        }
    }

先看看DirectToVoicemailCallFilter對象,它處理的是voicemail相關信息,

實際上是由CallerInfoLookupHelper完成查詢的,內部調用CallerInfoAsyncQueryFactory的startQuery方法,而CallerInfoAsyncQueryFactory是個接口類,在CallsManager創建的時候由外部傳參進來,最後找到是TelecomService的initializeTelecomSystem裡創建的

com.android.server.telecom.components. TelecomService
static void initializeTelecomSystem(Context context) {
   new CallerInfoAsyncQueryFactory() {
            @Override
           public CallerInfoAsyncQuery startQuery(
                 int token, Context context, String number, 
                 CallerInfoAsyncQuery.OnQueryCompleteListener listener,
                 Object cookie) {
                     Log.i(TelecomSystem.getInstance(),
                     "CallerInfoAsyncQuery.startQuery number=%s cookie=%s",
                     Log.pii(number), cookie);
                     return CallerInfoAsyncQuery.startQuery(
                     token, context, number, listener, cookie);
           }
 }

進入CallerInfoAsyncQuery的startQuery方法

com.android.internal.telephony.CallerInfoAsyncQuery
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
            OnQueryCompleteListener listener, Object cookie, int subId) {

 
 final Uri contactRef = PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI.buildUpon()
          .appendPath(number)
          .appendQueryParameter(PhoneLookup.QUERY_PARAMETER_SIP_ADDRESS,
          String.valueOf(PhoneNumberUtils.isUriNumber(number)))
          .build();
}

查詢的uri是PhoneLookup.ENTERPRISE_CONTENT_FILTER_URI

返回cursor結果集後轉化成CallerInfo,其中shouldSendToVoicemail變量查詢的

是PhoneLookup.SEND_TO_VOICEMAIL字段

public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) {
        ...... ......
        ...... ......
        columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL);
                info.shouldSendToVoicemail = (columnIndex != -1) &&
                        ((cursor.getInt(columnIndex)) == 1);
                info.contactExists = true;
        ...... ......
}

最後回到DirectToVoicemailCallFilter的查詢回調,shouldSendToVoicemail為true時表示允許通話,否則是拒接

if (info.shouldSendToVoicemail) {
    result = new CallFilteringResult(
                       false, // shouldAllowCall
                        true, // shouldReject
                        true, // shouldAddToCallLog
                        true // shouldShowNotification
                         );
    } else {
            result = new CallFilteringResult(
                         true, // shouldAllowCall
                           false, // shouldReject
                          true, // shouldAddToCallLog
                          true // shouldShowNotification
                          );
     }
}

再看看AsyncBlockCheckFilter,它處理的是黑名單事件

判斷一個電話號碼是否在黑名單裡調用到了BlockChecker的isBlocked方法

com.android.internal.telephony. BlockChecker
public static boolean isBlocked(Context context, String phoneNumber) {
        boolean isBlocked = false;
        long startTimeNano = System.nanoTime();

        try {
            if (BlockedNumberContract.SystemContract.shouldSystemBlockNumber(
                    context, phoneNumber)) {
                Rlog.d(TAG, phoneNumber + " is blocked.");
                isBlocked = true;
            }
        } catch (Exception e) {
            Rlog.e(TAG, "Exception checking for blocked number: " + e);
        }

        int durationMillis = (int) ((System.nanoTime() - startTimeNano) / 1000000);
        if (durationMillis > 500 || VDBG) {
            Rlog.d(TAG, "Blocked number lookup took: " + durationMillis + " ms.");
        }
        return isBlocked;
    }

BlockedNumberContract.SystemContract是framework裡的一個黑名單協議類

public static final String AUTHORITY = "com.android.blockednumber";
public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = 
"should_system_block_number";

public static boolean shouldSystemBlockNumber(Context context, String phoneNumber) {
            final Bundle res = context.getContentResolver().call(
                  AUTHORITY_URI, METHOD_SHOULD_SYSTEM_BLOCK_NUMBER, phoneNumber, null);
            return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
}

黑名單是BlockedNumberProvider數據庫, 調用call方法

com.android.providers.blockednumber. BlockedNumberProvider
@Override
public Bundle call(@NonNull String method, @Nullable String arg, @Nullable Bundle extras) {
        final Bundle res = new Bundle();
        switch (method) {
                case  SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER:
                    enforceSystemReadPermissionAndPrimaryUser();
                    res.putBoolean(
                    BlockedNumberContract.RES_NUMBER_IS_BLOCKED, shouldSystemBlockNumber(arg));
                break;
                ............
                ............
        }    
        
}

private boolean shouldSystemBlockNumber(String phoneNumber) {
    if (getBlockSuppressionStatus().isSuppressed) {
         return false;
    }
    if (isEmergencyNumber(phoneNumber)) {
        return false;
    }
    
    return isBlocked(phoneNumber);
}

最後調用isBlocked方法查詢blocked表中是否存在該number

查詢得到結果後返回

CallFilteringResult result;
        if (isBlocked) {
            result = new CallFilteringResult(
                    false, // shouldAllowCall
                    true, //shouldReject
                    false, //shouldAddToCallLog
                    false // shouldShowNotification
            );
        } else {
            result = new CallFilteringResult(
                    true, // shouldAllowCall
                    false, // shouldReject
                    true, // shouldAddToCallLog
                    true // shouldShowNotification
            );
        }

如果號碼在黑名單裡則攔截

最後是CallScreeningServiceFilter不知道是處理什麼,內部綁定一個抽象服務

CallScreeningService但是卻找不到哪個子類繼承了它,這裡先忽略它

回到前面IncomingCallFilter的onCallFilteringCompletev方法,結果集會做個邏輯運算

mResult = result.combine(mResult);看看它的實現

com.android.server.telecom.callfilteringCallFilteringResult
public CallFilteringResult combine(CallFilteringResult other) {
        if (other == null) {
            return this;
        }

        return new CallFilteringResult(
                shouldAllowCall && other.shouldAllowCall,
                shouldReject || other.shouldReject,
                shouldAddToCallLog && other.shouldAddToCallLog,
                shouldShowNotification && other.shouldShowNotification);
    }

只有三個過濾結果都是允許通話才允許通話,添加至通話記錄以及是否顯示到通知欄同理

當然這裡的查詢操作也有超時限制,時間是5秒,超過5秒後忽略還未查詢到的過濾器則被忽略mTimeoutsAdapter.getCallScreeningTimeoutMillis(mContext.getContentResolver()));

最後過濾結果被回調到CallsManager的onCallFilteringComplete

public void onCallFilteringComplete(Call incomingCall, CallFilteringResult result) {
   ………………………………
   if (incomingCall.getState() != CallState.DISCONNECTED &&
     incomingCall.getState() != CallState.DISCONNECTING) {
            setCallState(incomingCall, CallState.RINGING,
              result.shouldAllowCall 
? "successful incoming call" : "blocking call"
);
    } else {
       Log.i(this, "onCallFilteringCompleted: call already disconnected.");
    }

        if (result.shouldAllowCall) {
            if (hasMaximumRingingCalls()) {
                rejectCallAndLog(incomingCall);
            } else if (hasMaximumDialingCalls()) {
                rejectCallAndLog(incomingCall);
            } else {
                addCall(incomingCall);
            }
        } else {
            if (result.shouldReject) {
                incomingCall.reject(false, null);
            }
            if (result.shouldAddToCallLog) {
     
                mCallLogManager.logCall(incomingCall, Calls.MISSED_TYPE,
                        result.shouldShowNotification);
            } else if (result.shouldShowNotification) {

                mMissedCallNotifier.showMissedCallNotification(incomingCall);
            }
        }
    }

調用setCallState設置通話狀態為CallState.RINGING,接著判斷是否拒接,是否寫入通話記錄等, 正常情況下調用addCall方法

private void addCall(Call call) {
       ………………………………
        updateCallsManagerState();
        // onCallAdded for calls which immediately take the foreground (like the first call).
        for (CallsManagerListener listener : mListeners) {
            if (Log.SYSTRACE_DEBUG) {
                Trace.beginSection(listener.getClass().toString() + " addCall");
            }
            listener.onCallAdded(call);
            if (Log.SYSTRACE_DEBUG) {
                Trace.endSection();
            }
        }
        Trace.endSection();
    }

遍歷回調監聽者的onCallAdded方法,InCallController是其中一個觀察者,看看它的實現

com.android.server.telecom. InCallController
@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<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
                ComponentName componentName = entry.getKey();
                IInCallService inCallService = entry.getValue();
                ParcelableCall parcelableCall = ParcelableCallUtils.toParcelableCall(call,
                  true,mCallsManager.getPhoneAccountRegistrar());
                try {
                    inCallService.addCall(parcelableCall);
                } catch (RemoteException ignored) {
                }
            }
        }
    }

這裡的inCallService是個aidl接口,抽象服務InCallService的嵌套類InCallServiceBinder 實現了該接口

1.6 TelecommFramework

android.telecom. InCallService
private final class InCallServiceBinder extends IInCallService.Stub {
    @Override
        public void addCall(ParcelableCall call) {
            mHandler.obtainMessage(MSG_ADD_CALL, call).sendToTarget();
        }
    ...... ......
    ...... ......
}

handle對象處理消息MSG_ADD_CALL

private final Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
                case MSG_ADD_CALL:
                    mPhone.internalAddCall((ParcelableCall) msg.obj);
                    break;
     }
}

candroid.telecom.Phone
final void internalAddCall(ParcelableCall parcelableCall) {
        Call call 
= new Call(this
, parcelableCall.getId(), mInCallAdapter,
                parcelableCall.getState());
        mCallByTelecomCallId.put(parcelableCall.getId(), call);
        mCalls.add(call);
        checkCallTree(parcelableCall);
        call.internalUpdate(parcelableCall, mCallByTelecomCallId);
        fireCallAdded(call);
 }

 private void fireCallAdded(Call call) {
        for (Listener listener : mListeners) {
            listener.onCallAdded(this, call);
        }
  }

mPhone對象內部新建了一個call對象,獲取並轉化ParcelableCall的相關信息,並將call對象加入列表,最後回調Phone的監聽者的onCallAdded方法,這裡就是InCallService的

mPhoneListener成員變量

private Phone.Listener mPhoneListener = new Phone.Listener() {
        /** ${inheritDoc} */
          ...... ......


        /** ${inheritDoc} */
        @Override
        public void onCallAdded(Phone phone, Call call) {
            InCallService.this.onCallAdded(call);
        }
        ...... ......
    };

這裡InCallService的onCallAdded方法是一個抽象方法,具體實現在它的子類

1.7 Dialer

InCallServiceImpl繼承了InCallService,該服務在Dialer工程的manifest文件裡有聲明

<service android:name="com.android.incallui.InCallServiceImpl"
      android:permission="android.permission.BIND_INCALL_SERVICE"
      android:directBootAware="true" >
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" 
           android:value="true" />
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
           android:value="false"/>
      <intent-filter>
           <action android:name="
android.telecom.InCallService
"/>
      </intent-filter>
</service>

看看InCallServiceImpl的onCallAdded方法

com.android.incallui. InCallServiceImpl
  @Override
    public void onCallAdded(Call call) {
        InCallPresenter.getInstance().onCallAdded(call);
    }

InCallPresenter是incallui用於處理通話邏輯的核心類,內部就是各種業務邏輯操作,看看onCallAdded方法

com.android.incallui. InCallPresenter
public 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);
}

mCallList維護了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();
}

來電則調用onIncoming方法,其它call狀態則調用onUpdate方法,具體過程這裡就不詳述了,最終incallui拉起來電界面顯示,至此,一個來電的整體流程都分析完了,大致流程如下:

RIL→TelephonyFramework →TeleponyService→ TeleComService→

TeleComFramework→ TeleComService→TeleComFramework-->Dialer

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved