去電介面啟動分析---之一

Achillisjack發表於2017-08-16

1,去電介面啟動分析

在去電流程中論述過,會呼叫CallsManager的startOutgoingCall啟動撥號介面,在該方法中會呼叫addCall方法,

此時還處於services telecom程式中。

addCall(call);

addCall方法如下,

for (CallsManagerListener listener : mListeners) {
     if (Log.SYSTRACE_DEBUG) {
          Trace.beginSection(listener.getClass().toString() + " addCall");
     }
     listener.onCallAdded(call);
     if (Log.SYSTRACE_DEBUG) {
         Trace.endSection();
     }
}

mListeners定義如下,

private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(
      new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));

該雜湊表是執行緒安全的。

並且在CallsManager的構造方法中就會新增監聽器,

mListeners.add(mInCallController);
mListeners.add(mRinger);

當然,還可以呼叫addListener方法新增監聽器,

void addListener(CallsManagerListener listener) {
     mListeners.add(listener);
}

InCallController的onCallAdded方法主要邏輯如下,

1, 繫結InCallService服務

if (!isBoundToServices()) {//如果還沒有繫結
   bindToServices(call);
}

2,新增具體的call

for (Map.Entry<ComponentName, IInCallService> entry : mInCallServices.entrySet()) {
    ComponentName componentName = entry.getKey();
    IInCallService inCallService = entry.getValue();
    ParcelableCall parcelableCall = toParcelableCall(call, true /* includeVideoProvider */);
    try {
        inCallService.addCall(parcelableCall);
    } catch (RemoteException ignored) {
    }
}

3,電話狀態的變化,

onCallAudioStateChanged(null, mCallsManager.getAudioState());

1.1繫結InCallService服務

InCallController的bindToServices方法中會呼叫bindToInCallService方法,該方法如下,

Intent intent = new Intent(InCallService.SERVICE_INTERFACE);
intent.setComponent(componentName);
if (call != null && !call.isIncoming()){
    intent.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS,
          call.getIntentExtras());
    intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
          call.getTargetPhoneAccount());
}
Log.i(this, "Attempting to bind to [%s] InCall %s, with %s", tag, componentName, intent);
InCallServiceConnection inCallServiceConnection = new InCallServiceConnection();
if (mContext.bindServiceAsUser(intent, inCallServiceConnection,
   Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                    UserHandle.CURRENT)) {
   mServiceConnections.put(componentName, inCallServiceConnection);
   return true;
}

InCallService的SERVICE_INTERFACE變數如下,

public static final String SERVICE_INTERFACE = "android.telecom.InCallService";

InCallService只是一個抽象類,具體的實現在IncallUI  的InCallServiceImpl中, IncallUI 整個執行於dialer程式中。

InCallServiceImpl繼承於InCallService,

public class InCallServiceImpl extends InCallService {

Dialer的AndroidManifest.xml 中有關InCallServiceImpl如下,

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

由此可見,確認是啟動InCallServiceImpl無疑。

InCallServiceImpl的onBind方法會呼叫父類InCallService的onBind方法,

public IBinder onBind(Intent intent) {
   return new InCallServiceBinder();
}

返回的是InCallServiceBinder物件, InCallServiceBinder是InCallService的內部類,定義如下,

private final class InCallServiceBinder extends IInCallService.Stub {

因此,繫結的是dialer程式中的是InCallService的內部類InCallServiceBinder。

InCallServiceConnection是 InCallController的內部類,繫結成功之後,就會回撥InCallServiceConnection的

onServiceConnected方法,

public void onServiceConnected(ComponentName name, IBinder service) {
    Log.d(this, "onServiceConnected: %s", name);
    onConnected(name, service);
}

onConnected方法如下,

1,首先儲存繫結的遠端物件,

IInCallService inCallService = IInCallService.Stub.asInterface(service);
mInCallServices.put(componentName, inCallService);

2,呼叫繫結物件的setInCallAdapter方法,

inCallService.setInCallAdapter(new InCallAdapter(mCallsManager, mCallIdMapper, mLock));

dialer程式中的是InCallService的內部類InCallServiceBinder的setInCallAdapter方法下個小節詳細論述。

1.2設定InCallAdapter

InCallService的內部類InCallServiceBinder的setInCallAdapter方法如下,

public void setInCallAdapter(IInCallAdapter inCallAdapter) {
   mHandler.obtainMessage(MSG_SET_IN_CALL_ADAPTER, inCallAdapter).sendToTarget();
}

mHandler的handleMessage對MSG_SET_IN_CALL_ADAPTER訊息處理如下,

case MSG_SET_IN_CALL_ADAPTER:
    mPhone = new Phone(new InCallAdapter((IInCallAdapter) msg.obj));
    mPhone.addListener(mPhoneListener);
    onPhoneCreated(mPhone);
    break;

在構造Phone物件之前會構造InCallAdapter物件, InCallAdapter構造方法如下,

public InCallAdapter(IInCallAdapter adapter) {
     mAdapter = adapter;
}

mAdapter就是指向services Telephony的InCallAdapter物件。

這樣services telecom就可以通過binder進行跨程式呼叫。例如,結束通話電話/接聽電話等操作。

相關文章