Android 的 call setting 是用來設定與 simcard 相關的一些內容的應用程式,如網路,PIN等等,算是AP層。這裡就選擇其中一個項從原始碼讀下去直到底層,看看大概的結構和流程。
在 Android 主菜單中選擇 setting->call setting->additional call setting->caller ID,會彈出來一個對話方塊來選擇,這個項是用來設定在用電話本撥打到電話的時候是否顯示對方的電話號碼。這裡就以這個設定為例來一步步讀下去。
AP層:
call setting 的代碼和資源都是放在/packages/apps/Phone 的目錄下。其實 Android 的 setting AP 相關的資源都是放在/packages/apps/setting 下的。但是看 /packages/apps/Settings/res/xml/settings.xml 中:
<PreferenceScreen
android:key="call_settings" android:title="@string/call_settings_title" android:summary="@string/call_settings_summary">
<intent android:action="
android.intent.action.MAIN" android:targetPackage="
com.android.phone"
android:targetClass="
com.android.phone.CallFeaturesSetting" /> </PreferenceScreen>
從這裡就可以知道,android 的call setting 的包指向了 phone,並且知道了入口是 CallFeaturesSetting 類。在/packages/apps/Phone/res/call_featrue_setting.xml 中有call setting 的介面布局:<PreferenceScreen android:key="button_more_expand_key"
android:title="@string/labelMore"
android:persistent="false">...
<ListPreference android:key="button_clir_key" ... />這個button_clir_key就是對應的 caller ID 的那個按鈕,從這裡可以看出是一個ListPreference,點擊會出現一個列表框。裡面出現的內容布局都在這裡定義。相關的xml檔都在/packages/apps/Phone/res 下。接著就是AP的代碼了,在/packages/apps/Phone/src 下。前面說了入口是 CallFeaturesSetting:public class CallFeaturesSetting extends PreferenceActivity {
…
private PreferenceScreen mSubMenuFDNSettings;
private ListPreference mButtonCLIR;
private CheckBoxPreference mButtonCW;
...
protected
void onCreate(…) {
…
PreferenceScreen prefSet = getPreferenceScreen();
mButtonCLIR = (ListPreference) prefSet.findPreference(BUTTON_CLIR_KEY);
...
定義的 mButtonCLIR 就是對應caller ID 的變數。在onCreate中初始化,用findPreference來找到XML中對應的資源。
然後是對這個按鈕的響應代碼:
public
boolean onPreferenceChange(Preference
preference, Object objValue){
if (preference == mButtonCLIR) {
handleCLIRClickRequest(mButtonCLIR.findIndexOfValue((String)
objValue));
...
}
private
void handleCLIRClickRequest(int i) {
…
mPhone.setOutgoingCallerIdDisplay(i,Message.obtain(mSetOptionComplete, EVENT_CLIR_EXECUTED));
}
可以看到最終是調用 mPhone.setOutgoingCallerIdDisplay 來完成真正的設定。這個 mPhone 是
com.android.internal.telephony.Phone,mPhone 的調用就進入 framework 層了。
Framework層:
相關的代碼在/frameworks/base/telephony/java 中。先從 Phone 開始,這是一個 interface,真正實現是在
com.android.internal.telephony.gsm.GSMPhone 中:
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
mCM.setCLIR(commandInterfaceCLIRMode,
h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
}
這裡是調用 mCM.setCLIR。mCM 是一個 CommandsInterface,真正實現是在 RIL.java 檔案中。這下到了framework中
真正辦實事的地方。同樣是在com.android.internal.telephony.gsm 下,RIL類中:
public void setCLIR(int clirMode, Message result)
{
RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result);
rr.mp.writeInt(1);
rr.mp.writeInt(clirMode);
...
send(rr);
}
這裡順便說一下,RIL與底層是用socket來通訊。所以send(rr)最終是把RIL_REQUEST_SET_CLIR發給底層,底層會有一個守護
進程來接收framework層的資訊,並且把結果傳達上去。繼續看下send的代碼:
private void send(RILRequest rr)
{
Message msg;
msg = mSender.obtainMessage(EVENT_SEND, rr);
acquireWakeLock();
msg.sendToTarget();
}
是發一個EVENT_SEND的message給系統。那麼找這個 handle 這個 message 的地方,還是同一個檔案裡,RIL.RILSender類
裡面的handleMessage:
public void handleMessage(Message msg)
{
RILRequest rr = (RILRequest)(msg.obj);
switch (msg.what) {
case EVENT_SEND:
LocalSocket s;
s = mSocket;
...
byte[] data;
data = rr.mp.marshall();
rr.mp.recycle();
rr.mp = null;
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
...
這裡的mSocket 在就是與底層溝通的socket,有興趣可以看看相關代碼。
到這裡 framework 層也算告一段落,在下去就是底層的C部分了。放在下一篇文章在寫吧。