Android拨号盘特殊字符串(例如*#06#显示IMEI或者MEID)处理的类是:
packages/apps/Dialer/src/com/android/dialer/SpecialCharSequenceMgr.java,入口是handleChars,这个方法在拨号盘EditText字符有变化的时候会调用:
public static boolean handleChars(Context context, String input, EditText textField) { //get rid of the separators so that the string gets parsed correctly String dialString = PhoneNumberUtils.stripSeparators(input); if (ZteEngineerCode.handleZteEngineerCode(context, dialString) || handleDeviceIdDisplay(context, dialString) || handleRegulatoryInfoDisplay(context, dialString) || handlePinEntry(context, dialString) || handleAdnEntry(context, dialString, textField) || ZteEngineerCode.handleZteEngineerCode(context, dialString) || handleSecretCode(context, dialString) /// M: for plug-in @{ || ExtensionManager.getInstance().getDialPadExtension().handleChars(context, dialString) /// @} ) { return true; } return false; }一个有多个处理函数组成的if判断语句作为主体,只有有一个方法返回true就返回。 static boolean handleDeviceIdDisplay(Context context, String input) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager != null && input.equals(MMI_IMEI_DISPLAY)) { int labelResId = (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) ? R.string.imei : R.string.meid; List<String> deviceIds = new ArrayList<String>(); for (int slot = 0; slot < telephonyManager.getPhoneCount(); slot++) { String deviceId = telephonyManager.getDeviceId(slot); if (!TextUtils.isEmpty(deviceId)) { deviceIds.add(deviceId); } } /// M: Add single IMEI plugin. @{ deviceIds = ExtensionManager.getInstance().getDialPadExtension().getSingleIMEI( deviceIds); /// @} AlertDialog alert = new AlertDialog.Builder(context) .setTitle(labelResId) .setItems(deviceIds.toArray(new String[deviceIds.size()]), null) .setPositiveButton(android.R.string.ok, null) .setCancelable(false) .show(); return true; } return false; }拿*#06#举例,使用TelephonyManager获取相应信息后弹出AlertDialog显示。ZteEngineerCode是mtk相关的暗码处理类,流程类似handleChars,单独类分离出去不和原生代码掺杂在一起
handleRegulatoryInfoDisplay处理*#07#,发送了个Intent出去,处理该intent的是设置中的代码:
<!-- Show regulatory info (from settings item or dialing "*#07#") --> <activity android:name="RegulatoryInfoDisplayActivity" android:label="@string/regulatory_information" android:taskAffinity="" android:enabled="@bool/config_show_regulatory_info"> <intent-filter> <action android:name="android.settings.SHOW_REGULATORY_INFO" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true" /> </activity>显示手机相关的一些信息,不过我看源码中这个相关字符串是空的,实际手机验证啥也没弹出来,activity收到intent后会马上关闭。handlePinEntry处理一些Mmi码,详细见MMI SS USSD扫盲贴:
static boolean handlePinEntry(final Context context, final String input) { if ((input.startsWith("**04") || input.startsWith("**05")) && input.endsWith("#")) { ... return TelecomUtil.handleMmi(context, input, null); ... }**04和**05开头的mmi码都是设置pin的,所以该方法有pin这个字眼,很少人知道有个东西吧。handleAdnEntry,adn就是卡联系人,输入数字(1~4位)加#结束,拨号盘会自动加载sim卡对应index卡联系人的号码(如果有的话)
handleSecretCode发送一个广播,*#*#开头和#*#*结尾的字符串都会看成是secretcode:
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("#*#*")) { final Intent intent = new Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://" + input.substring(4, len - 4))); context.sendBroadcast(intent); return true; } return false; }还是设置中的例子,*#*#4636#*#*可以开启一个activity,显示手机很多信息,如注册的网络信息,电池信息,wifi信息等。 <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>如果需要加入暗码需求统一使用广播模式是最好的,不用更改代码其它应用就可以有暗码入口,不过可惜运营商定制机器有很多强制要实现的暗码。