編輯:關於android開發
接上篇博文:Android7.0 Phone應用源碼分析(一) phone撥號流程分析
今天我們再來分析下Android7.0 的phone的來電流程
當有來電通知時,首先接收到消息的是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
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方法
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方法
再把實現代碼貼一遍:
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的回調
前面提到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(newAsyncBlockCheckFilter
(mContext, new BlockCheckerAdapter())); filters.add(new CallScreeningServiceFilter(mContext, this, mPhoneAccountRegistrar, mDefaultDialerManagerAdapter, new ParcelableCallUtils.Converter(), mLock)); newIncomingCallFilter
(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 實現了該接口
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方法是一個抽象方法,具體實現在它的子類
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
android ListView詳解,androidlistview由於google doc 很多人都打不開,故更新了源碼下載地址 【源碼下載】----2011-01-1
Android中的LinearLayout布局,linearlayout垂直布局LinearLayout : 線性布局
QQ空間實現(一)—— 展示說說中的評論內容並有相應點擊事件,評論內容事件大家都玩QQ空間客戶端,對於每一個說說,我們都可以評論,那麼,對於某一條評論: 白雪公主 回復
Android包含了常用於嵌入式系統的SQLite,免去了開發者自己移植安裝的功夫。SQLite