首页 > 代码库 > Android指令处理流程源码追踪

Android指令处理流程源码追踪

1.拨号界面输入*#06#,显示IMEI号,这是怎么出来的?

2.如何快速的找出Android平台中的指令?


1. 在DialpadFragment中的EditText注册一个Textchanged的监听器TextWatcher,

   当EditText中的内容发生变化时会调用相应的回调函数,TextWatcher是一个接口:

public interface TextWatcher extends NoCopySpan {
    public void beforeTextChanged(CharSequence s, int start,int count, int after);
    public void onTextChanged(CharSequence s, int start, int before, int count);
    public void afterTextChanged(Editable s);
}
在DialpadFragment中实现了该接口:

    public void afterTextChanged(Editable input) {
        // When DTMF dialpad buttons are being pressed, we delay SpecialCharSequencMgr sequence,
        // since some of SpecialCharSequenceMgr's behavior is too abrupt for the "touch-down"
        // behavior.
        if (!mDigitsFilledByIntent &&
                SpecialCharSequenceMgr.handleChars(getActivity(), input.toString(), mDigits)) {
            // A special sequence was entered, clear the digits
            mDigits.getText().clear();
        }
        if (isDigitsEmpty()) {
            mDigitsFilledByIntent = false;
            mDigits.setCursorVisible(false);
        }else {
		mDigits.setCursorVisible(true);  
	}

        updateDialAndDeleteButtonEnabledState();
        loadSmartDialEntries();

        refreshDigitTextSize(input);
    }
指令处理的主角:SpecialCharSequenceMgr.handleChars(getActivity(), input.toString(), mDigits)

看 其方法的主体:

    static boolean handleChars(Context context, String input, boolean useSystemWindow,
            EditText textField) {

        //get rid of the separators so that the string gets parsed correctly
        String dialString = PhoneNumberUtils.stripSeparators(input);

        if (handlePRLVersion(context, dialString)
                || handleModemTestDisplay(context, dialString)
                || handleIMEIDisplay(context, dialString, useSystemWindow)
                || handleRegulatoryInfoDisplay(context, dialString)
                || handlePinEntry(context, dialString)
                || handleAdnEntry(context, dialString, textField)
                || handleSecretCode(context, dialString)
            return true;
        }

        return false;
    }
这里有个handleIMEIDisplay(context, dialString, useSystemWindow),看其主体:

    static boolean handleIMEIDisplay(Context context, String input, boolean useSystemWindow) {
        if (input.equals(MMI_IMEI_DISPLAY)) {   <span style="color:#3333ff;"> //</span><span style="font-family: Arial, Helvetica, sans-serif;"><span style="color:#3333ff;">MMI_IMEI_DISPLAY = "*#06#"</span></span>
            if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
                return handleMSimIMEIDisplay(context);<span style="background-color: rgb(255, 255, 255);"><span style="color:#3333ff;">//显示IMEI号</span></span>
            }
            int subscription = MSimTelephonyManager.getDefault().getPreferredVoiceSubscription();
            int phoneType;
            if (MSimTelephonyManager.getDefault().isMultiSimEnabled()) {
                phoneType = ((MSimTelephonyManager)context.getSystemService(
                        Context.MSIM_TELEPHONY_SERVICE)).getCurrentPhoneType(subscription);
            } else {
                phoneType = ((TelephonyManager)context.getSystemService(
                        Context.TELEPHONY_SERVICE)).getCurrentPhoneType();
            }
         if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
                showIMEIPanel(context, useSystemWindow);<span style="font-family: Arial, Helvetica, sans-serif;"><span style="color:#3333ff;">//显示IMEI号</span></span>
                return true;
            } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
                showMEIDPanel(context, useSystemWindow);<span style="font-family: Arial, Helvetica, sans-serif;"><span style="color:#3333ff;">//显示IMEI号</span></span>
                return true;
            }
        }

        return false;
    }
至此IMEI号的显示流程都呈现出来。

2.在handleChars中还有对其他指令进行处理的方法:

handleModemTestDisplay、handleRegulatoryInfoDisplay、handleSecretCode等,

其中handleSecretCode是对*#*#。。#*#* 这一类的指令进行集中处理,看源码:

  static boolean handleSecretCode(Context context, String input) {
        // Secret codes are in the form *#*#<code>#*#*
        int len = input.length();
        if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {

            Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
                    Uri.parse("android_secret_code://" + input.substring(4, len - 4)));
            context.sendBroadcast(intent);
            return true;
        }

        return false;
    }
可以看到是发送的一个广播,广播的action是 :

public static final String SECRET_CODE_ACTION ="android.provider.Telephony.SECRET_CODE";
data是一个URI,

所以在平台里面的所有AndroidManifest.xml 文件中查找android.provider.Telephony.SECRET_CODE,

即可找出平台中所有*#*#。。#*#* 类型的指令,如:

<receiver android:name="TestingSettingsBroadcastReceiver">
            <intent-filter>
                 <action android:name="android.provider.Telephony.SECRET_CODE" />
                 <data android:scheme="android_secret_code" android:host="837851" />
            </intent-filter>
</receiver>


     <receiver android:name="TestingSettingsBroadcastReceiver">
            <intent-filter>
                 <action android:name="android.provider.Telephony.SECRET_CODE" />
                 <data android:scheme="android_secret_code" android:host="4636" />
            </intent-filter>
       </receiver>