什么是暗码?
在拨号盘中输入 *#*#<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, 收功.
来源: https://www.cnblogs.com/WuXiaolong/p/11187423.html