首先看下framework的入口函数PhoneUtils.placeCall
public static int placeCall(Context context, Phone phone,
String number, Uri contactRef, boolean isEmergencyCall,
Uri gatewayUri) {
final PhoneApp app = PhoneApp.getInstance();
if (useGateway) {
..
numberToDial = gatewayUri.getSchemeSpecificPart();
} else {
numberToDial = number;
}
connection = app.mCM.dial(phone, numberToDial);
...
number = PhoneNumberUtils.extractNetworkPortion(number);
number = PhoneNumberUtils.convertKeypadLettersToDigits(number);
number = PhoneNumberUtils.formatNumber(number);
...
connection.setUserData(..)
...
setAudioMode();
activateSpeakerIfDocked(phone);
}
这里无论怎么样都会将Number转换为numberToDial然后调用CallManager.dial的方法打电话。然后会把number转换为相对应的打电话者的信息存入Connection中。 setAudioMode()设置声音模式,activateSpeakerIfDocked()根据外设情况,是否打开麦克.
看下CallManager.dial的代码
public Connection dial(Phone phone, String dialString) throws CallStateException {
Phone basePhone = getPhoneBase(phone);
if ( hasActiveFgCall() ) {
Phone activePhone = getActiveFgCall().getPhone();
boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
if (activePhone != basePhone) {
if (hasBgCall) {
Log.d(LOG_TAG, "Hangup");
getActiveFgCall().hangup();
} else {
Log.d(LOG_TAG, "Switch");
activePhone.switchHoldingAndActive();
}
}
}
result = basePhone.dial(dialString);
}
这里应该比较好理解,主要看下getPhoneBase的作用就好了。
private static Phone getPhoneBase(Phone phone) {
if (phone instanceof PhoneProxy) {
return phone.getForegroundCall().getPhone();
}
return phone;
}
public Phone
getPhone() {
return owner.phone;
}
GsmCall (GsmCallTracker owner) {
this.owner = owner;
}
主要就是根据当前电话类型,返回不同的电话对象.
basePhone.dial,则是调用GSMPhone.dial(如果电话为CDMAPhone,则会调用CDMAPhone.dial)
public Connection
dial (String dialString, UUSInfo uusInfo) throws CallStateException {
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
..
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication);
if (mmi == null) {
return mCT.dial(newDialString, uusInfo);
} else if (mmi.isTemporaryModeCLIR()) {
return mCT.dial(mmi.dialingNumber, mmi.getCLIRMode(), uusInfo);
} else if (SystemProperties.getBoolean("ro.config.multimode_cdma", false) &&
mmi.isGlobalDevMmi()) {
return mCT.dial(mmi.dialingNumber, uusInfo);
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
mmi.processCode();
return null;
}
}
这里好像是对网络电话做了处理,笔者具体也不是很清楚。看下其他电话的流程。
会调用mCT.dial,既是调用GsmCallTracker.dial
dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException {
...
cm.dial(pendingMO.address, clirMode, uusInfo, obtainCompleteMessage());
...
updatePhoneState();
phone.notifyPreciseCallStateChanged();
}
其中cm.dial进入RIL层,调用dial方法.
updatePhoneState方法会更新当前电话的状态。然后调用notifyPreciseCallStateChanged进行通知,因为在InCallScreen的OnCreat()方法中注册了registerForPhoneStates状态改变,所以上层会收到通知做出相对应的改变.
让我们看下RIL.dial
public void
dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
rr.mp.writeString(address);
rr.mp.writeInt(clirMode);
rr.mp.writeInt(0); // UUS information is absent
if (uusInfo == null) {
rr.mp.writeInt(0); // UUS information is absent
} else {
rr.mp.writeInt(1); // UUS information is present
rr.mp.writeInt(uusInfo.getType());
rr.mp.writeInt(uusInfo.getDcs());
rr.mp.writeByteArray(uusInfo.getUserData());
}
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
后面的就比较容易了,我们直接看ril中RILSender的case EVENT_SEND。
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
..
LocalSocket s;
s = mSocket;
..
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
}
这里会向socket中写信息.而RILReciver那里一开始就建立了socket的连接,与rild通信。
class RILReceiver implements Runnable {
...
if (mInstanceId == null || mInstanceId == 0 || multiRild == false) {
rilSocket = SOCKET_NAME_RIL;
} else {
rilSocket = SOCKET_NAME_RIL1;
}
try {
s = new LocalSocket();
l = new LocalSocketAddress(rilSocket,
LocalSocketAddress.Namespace.RESERVED);
s.connect(l);
....
}
static final String SOCKET_NAME_RIL = "rild";
static final String SOCKET_NAME_RIL1 = "rild1";
至此,framework层结束