編輯:關於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(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 實現了該接口
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
android ListView詳解,androidlistview由於google doc 很多人都打不開,故更新了源碼下載地址 【源碼下載】----2011-01-1
Android中的LinearLayout布局,linearlayout垂直布局
Android中的LinearLayout布局,linearlayout垂直布局LinearLayout : 線性布局
QQ空間實現(一)—— 展示說說中的評論內容並有相應點擊事件,評論內容事件
QQ空間實現(一)—— 展示說說中的評論內容並有相應點擊事件,評論內容事件大家都玩QQ空間客戶端,對於每一個說說,我們都可以評論,那麼,對於某一條評論: 白雪公主 回復
Android提高21篇之八:SQLite分頁讀取
Android包含了常用於嵌入式系統的SQLite,免去了開發者自己移植安裝的功夫。SQLite