Android 装逼技术之暗码启动应用
作者:吴小龙同學 | 公众号:吴小龙同學
什么是暗码?
在拨号盘中输入*#*#<code>#*#*
后,APP 可以监控到这些输入,然后做相应的动作,比如启动应用,是不是有点骚。
下面看下这个骚操作是如何实现的。
效果预览
![](/assets/blank.gif)
源码
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); } //……} //…… 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(); } //……}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;} // 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;} // 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); }} // 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> <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); } }}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,收功。
END
这篇文章来自公众号「吴小龙同学」,据我了解,号主是一个非常爱折腾的一线码农,目前在国内 TOP 3 手机厂商上班,8 年互联网经验,看他常年乐于分享,涉及很广,在 Java、Python、Android、大前端、程序员职业发展等方面都有很多干货文章输出,墙裂推荐你扫描下方二维码也关注一下!
Android 装逼技术之暗码启动应用相关推荐
- android中暂停服务,Android 装逼技术之暗码启动应用
前言 喜欢的小伙伴欢迎关注,我会定期分享Android知识点及解析,还会不断更新的BATJ面试专题,欢迎大家前来探讨交流,如有好的文章也欢迎投稿. 什么是暗码? 在拨号盘中输入*#*##*#*后,AP ...
- Android 系统(125)---Android通过Dialer实现暗码启动
Android通过Dialer实现暗码启动 目前接触比较多的就是通过dialer应用来启动/触发暗码. 本文以Dialer为例, 1.经过调试定位,发现拨号盘接对应的Activity为Dialtact ...
- 通过Dialer拨号盘输暗码启动某个apk
通过拨号暗码 启动某个apk 首先\packages\apps\Dialer\src\com\android\dialer\SpecialCharSequenceMgr.java 定义了这个方法 /* ...
- 21条精通程序员装逼技术
1. 电脑一定不能盖机箱盖,用来表示自己拆装机小CASE且经常升级自己用了四五年的破电脑<br><br> 2. 桌上必须散放各种内存条 优盘 或者拆开的光驱硬盘报废的CPU等 ...
- java装逼的话_Java 源码装逼技能之让人懵逼的符号
源码就是符号位 + 二级制数值.符号位是第一位,0 表示正数,1 表示负数. Java 中 byte 类型一字节八位,可以表示 [1111 1111 , 0111 1111],取值 [-127,127 ...
- Linux命令行五大装B技术
最近在不务正业, 搞搞一些别的东西, 为了能让我们程序员在生活中有装逼的资本, 因此搜集了一些Linux上的装逼技术. 下面,是时候展现真正的技术了~~~ 使用的阿里云的Ecs服务器以及Xshell实 ...
- Android+Web视频直播装逼实现
一.前言 因为最近视频直播比较火,自己也想去了解,所以看了一些资料分享一下,说错了的请大家包容和指正. 二.实现原理 看图说话: 通过上图可以看到,所谓的视频直播其实就是通过录相设备将采集到视频数据以 ...
- 从源码角度看Android系统Launcher在开机时的启动过程
Launcher是Android所有应用的入口,用来显示系统中已经安装的应用程序图标. Launcher本身也是一个App,一个提供桌面显示的App,但它与普通App有如下不同: Launcher是所 ...
- android swf 播放器代码,Android Flash swf播放器源码(2016),技术稳定可以商用—— BY softboy...
Android Flash swf播放器源码(2016) 为什么说标题加上2016? 其实不是什么新技术,因为android4.1之后的android 浏览器内核版本发生了变化导致 Adobe 的Fl ...
最新文章
- CMake结合Visual Studio中开发Qt应用程序注意事项
- MVC案例——模糊查询
- xcode 5 使用 XCTest 做单元测试
- 【opencv有趣应用】二维码和条形码的检测
- (三)微调VGG16以对服装进行分类
- 云服务器上传文件到哪个文件夹,云服务器上传到那个文件夹
- C#问题——interface class
- [Android Pro] 内容提供者ContentProvider的基本使用
- Flink Forward Asia 2020,明天见!
- HSRP 和 VRRP 协议
- fiddler显示客户端请求时间
- Linux驱动开发-编写OLED显示屏驱动
- 2021-11-25 使用kali自带的SET工具制作钓鱼网站
- ASO优化教程:产品预热与应用提交aso主要优化,ASO优化
- 最全英语日期相关表达
- 【松鼠科学会】头脑练功房:冥想真的有效吗?
- pyscripter与python的关系_Pyscripter是python下一个非常流行的开源IDE
- 自动化测试处理textarea文本框
- 表单reset重置按钮的作用并非是清空表单
- css hover变成手_css鼠标样式cursor介绍(鼠标手型)