什么是暗码?

在拨号盘中输入*#*#<code>#*#*后,APP 可以监控到这些输入,然后做相应的动作,比如启动应用,是不是有点骚。

下面看下这个骚操作是如何实现的。

效果预览



源码

DialtactsActivity#showDialpadFragment

DialtactsActivity 中有个 showDialpadFragment 方法,用来加载显示拨号盘,因此入口就从
showDialpadFragment 看起,基于 Android P 分析。
private void showDialpadFragment(boolean animate) { //…… final
FragmentTransaction ft = getFragmentManager().beginTransaction(); if
(dialpadFragment == null) { dialpadFragment = new DialpadFragment();
ft.add(R.id.dialtacts_container, dialpadFragment, TAG_DIALPAD_FRAGMENT); } else
{ ft.show(dialpadFragment); } //…… }
具体实现在 DialpapFragment 中,看到 DialpapFragment 实现了 TextWatcher,TextWatcher 有 3
个重要方法,分别为:beforeTextChanged,onTextChanged 和 afterTextChanged,重点看
afterTextChanged 方法。

DialpadFragment#afterTextChanged
public class DialpadFragment extends Fragment implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener, AdapterView.OnItemClickListener,
TextWatcher, PopupMenu.OnMenuItemClickListener,
DialpadKeyButton.OnPressedListener { //…… @Override public void
afterTextChanged(Editable input) { // When DTMF dialpad buttons are being
pressed, we delay SpecialCharSequenceMgr sequence, // since some of
SpecialCharSequenceMgr's behavior is too abrupt for the "touch-down" //
behavior. if (!digitsFilledByIntent &&
SpecialCharSequenceMgr.handleChars(getActivity(), input.toString(), digits)) {
// A special sequence was entered, clear the digits digits.getText().clear(); }
if (isDigitsEmpty()) { digitsFilledByIntent = false;
digits.setCursorVisible(false); } if (dialpadQueryListener != null) {
dialpadQueryListener.onDialpadQueryChanged(digits.getText().toString()); }
updateDeleteButtonEnabledState(); } //…… }
这里调用了 SpecialCharSequenceMgr 辅助工具类的 handleChars 方法,看这个方法。

SpecialCharSequenceMgr#handleChars
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
(handleDeviceIdDisplay(context, dialString) ||
handleRegulatoryInfoDisplay(context, dialString) || handlePinEntry(context,
dialString) || handleAdnEntry(context, dialString, textField) ||
handleSecretCode(context, dialString)) { return true; } if
(MotorolaUtils.handleSpecialCharSequence(context, input)) { return true; }
return false; }
handleChars 方法中,会对各种特殊的 secret code 进行匹配处理,这里我们看 handleSecretCode。

SpecialCharSequenceMgr#handleSecretCode
static boolean handleSecretCode(Context context, String input) { // Secret
code specific to OEMs should be handled first. if
(TranssionUtils.isTranssionSecretCode(input)) {
TranssionUtils.handleTranssionSecretCode(context, input); return true; } //
Secret codes are accessed by dialing *#*#<code>#*#* or
"*#<code_starting_with_number>#" if (input.length() > 8 &&
input.startsWith("*#*#") && input.endsWith("#*#*")) { String secretCode =
input.substring(4, input.length() - 4);
TelephonyManagerCompat.handleSecretCode(context, secretCode); return true; }
return false; }
再看下 TelephonyManagerCompat.handleSecretCode 方法。

TelephonyManagerCompat#handleSecretCode
public static void handleSecretCode(Context context, String secretCode) { //
Must use system service on O+ to avoid using broadcasts, which are not allowed
on O+. if (BuildCompat.isAtLeastO()) { if
(!TelecomUtil.isDefaultDialer(context)) { LogUtil.e(
"TelephonyManagerCompat.handleSecretCode", "not default dialer, cannot send
special code"); return; }
context.getSystemService(TelephonyManager.class).sendDialerSpecialCode(secretCode);
} else { // System service call is not supported pre-O, so must use a broadcast
for N-. Intent intent = new Intent(SECRET_CODE_ACTION,
Uri.parse("android_secret_code://" + secretCode));
context.sendBroadcast(intent); } }
可以看到在拨号中接收到*#*#<code>#*#* 这样的指令时,程序会对外发送广播,这就意味着我们能够接收这个广播然后可以做我们想做的事情。

接下来我们看看这个接受广播代码是怎么写。

应用

首先在 AndroidManifest 文件中注册广播接收器。
<receiver android:name=".SecretCodeReceiver"> <intent-filter> <action
android:name="android.provider.Telephony.SECRET_CODE" /> <data
android:scheme="android_secret_code" android:host="1010" /> </intent-filter>
</receiver>
接收广播,启动应用。
public class SecretCodeReceiver extends BroadcastReceiver { @Override public
void onReceive(Context context, Intent intent) { if (intent != null &&
SECRET_CODE_ACTION.equals(intent.getAction())){ Intent i = new
Intent(Intent.ACTION_MAIN); i.setClass(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(i); } } }
这样只要在拨号中输入*#*#1010#*#*就能启动相应的应用程序,OK,收功。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信