源码分析之Android通过Dialer实现暗码启动

2024-09-06 09:08

本文主要是介绍源码分析之Android通过Dialer实现暗码启动,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目前接触比较多的就是通过dialer应用来启动/触发暗码。

也有通过Calculator来实现的。

本文以Dialer为例,

1.经过调试定位,发现拨号盘接对应的Activity为DialtactsActivity。

2.DialtactsActivity中有个showDialpadFragment方法,用来加载显示拨号盘,因为有可能此时拨号盘正处于收缩/隐藏状态。

    /*** Initiates a fragment transaction to show the dialpad fragment. Animations and other visual* updates are handled by a callback which is invoked after the dialpad fragment is shown.* @see #onDialpadShown*/private void showDialpadFragment(boolean animate) {if (mIsDialpadShown || mStateSaved) {return;}mIsDialpadShown = true;mListsFragment.setUserVisibleHint(false);final FragmentTransaction ft = getFragmentManager().beginTransaction();if (mDialpadFragment == null) {mDialpadFragment = new DialpadFragment();ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);} else {ft.show(mDialpadFragment);}//mDialpadFragment.setAnimate(animate);AnalyticsUtil.sendScreenView(mDialpadFragment);ft.commit();maybeEnterSearchUi();if (animate) {mFloatingActionButtonController.scaleOut();} else {mFloatingActionButtonController.setVisible(false);}mActionBarController.onDialpadUp();mListsFragment.getView().animate().alpha(0).withLayer();}

3.接下来重点处理实现就在DialpapFragment中,首先来看类的声明/继承。

import com.android.dialer.dialpad.DialpadFragment;

/*** Fragment that displays a twelve-key phone dialpad.*/
public class DialpadFragment extends Fragmentimplements View.OnClickListener,View.OnLongClickListener, View.OnKeyListener,AdapterView.OnItemClickListener, TextWatcher,PopupMenu.OnMenuItemClickListener,DialpadKeyButton.OnPressedListener,/// M: add for plug-in @{DialpadExtensionAction {

从以上类实现/继承中可以发现,其继承了TextWatcher类,也正是这个类使之能够监听实现输入变化。

TextWatcher有3个重要方法,分别为:beforeTextChanged,onTextChanged和afterTextChanged。分别看下面那份源码。


onTextChanged


其中最重点的是afterTextChanged方法,其调用了SpecialCharSequenceMgr辅助工具类的handleChars方法。


4.handleChars方法中,会对各种特殊的secret code进行匹配处理。

    public static boolean handleChars(Context context, String input, EditText textField) {//get rid of the separators so that the string gets parsed correctlyString dialString = PhoneNumberUtils.stripSeparators(input);if (handleDeviceIdDisplay(context, dialString) //*#06#|| handleRegulatoryInfoDisplay(context, dialString)|| handlePinEntry(context, dialString)|| handleAdnEntry(context, dialString, textField)|| handleSecretCode(context, dialString) //for the form of *#*#<code>#*#*./// @}/// M: for plug-in @{|| ExtensionManager.getInstance().getDialPadExtension().handleChars(context,dialString)/// @}) {return true;}return false;}
5.接下来分开两种讲,一种是直接弹出对话框的那种,类如*#06#,另一种则是调起别的应用等方式。
5.1 )*#*#<code>#*#*

    /*** Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.* If a secret code is encountered an Intent is started with the android_secret_code://<code>* URI.** @param context the context to use* @param input the text to check for a secret code in* @return true if a secret code was encountered*/static boolean handleSecretCode(Context context, String input) {// Secret codes are in the form *#*#<code>#*#*/// M: for plug-in @{input = ExtensionManager.getInstance().getDialPadExtension().handleSecretCode(input);/// @}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)));///android_secret_code://287context.sendBroadcast(intent);return true;}return false;}
有以上代码可知,最终是通过broadcast发送出去的,并往intent里面加载了2种数据:Uri和Action。

Action:

private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
接受端的注册方式,Action 和 data必须和发送的broadcast相匹配才行:

/vendor/mediatek/proprietary/packages/apps/EngineerMode/AndroidManifest.xml

        <receiverandroid:name=".EngineerModeReceiver"android:exported="true" ><intent-filter><action android:name="android.provider.Telephony.SECRET_CODE" /><dataandroid:host="3646633"android:scheme="android_secret_code" /></intent-filter></receiver>

/vendor/mediatek/proprietary/packages/apps/EngineerMode/src/com/mediatek/engineermode/EngineerModeReceiver.java


由上面代码可知,这就对应上了,在Receiver接受到广播后,启动对应的应用/Activity来处理接下来的工作。


5.2 )*#06#  直接在Context中弹出对话框,显示IMEI信息

/packages/apps/Dialer/src/com/android/dialer/SpecialCharSequenceMgr.java

    // TODO: Use TelephonyCapabilities.getDeviceIdLabel() to get the device id label instead of a// hard-coded string.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>();if (TelephonyManagerCompat.getPhoneCount(telephonyManager) > 1 &&CompatUtils.isMethodAvailable(TelephonyManagerCompat.TELEPHONY_MANAGER_CLASS,"getDeviceId", Integer.TYPE)) {for (int slot = 0; slot < telephonyManager.getPhoneCount(); slot++) {String deviceId = telephonyManager.getDeviceId(slot);if (!TextUtils.isEmpty(deviceId)) {deviceIds.add(deviceId);}}} else {deviceIds.add(telephonyManager.getDeviceId());}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();///直接在Context中弹出对话框,显示IMEI信息return true;}return false;}

*#07# 直接通过隐式intent启动相关应用

    private static boolean handleRegulatoryInfoDisplay(Context context, String input) {if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {Log.d(TAG, "handleRegulatoryInfoDisplay() sending intent to settings app");Intent showRegInfoIntent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);try {context.startActivity(showRegInfoIntent);} catch (ActivityNotFoundException e) {Log.e(TAG, "startActivity() failed: " + e);}return true;}return false;}

以上就是Android通过Dialer方式启动暗码的大致源码流程分析。


这篇关于源码分析之Android通过Dialer实现暗码启动的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141592

相关文章

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

Python pyinstaller实现图形化打包工具

《Pythonpyinstaller实现图形化打包工具》:本文主要介绍一个使用PythonPYQT5制作的关于pyinstaller打包工具,代替传统的cmd黑窗口模式打包页面,实现更快捷方便的... 目录1.简介2.运行效果3.相关源码1.简介一个使用python PYQT5制作的关于pyinstall

使用Python实现大文件切片上传及断点续传的方法

《使用Python实现大文件切片上传及断点续传的方法》本文介绍了使用Python实现大文件切片上传及断点续传的方法,包括功能模块划分(获取上传文件接口状态、临时文件夹状态信息、切片上传、切片合并)、整... 目录概要整体架构流程技术细节获取上传文件状态接口获取临时文件夹状态信息接口切片上传功能文件合并功能小

python实现自动登录12306自动抢票功能

《python实现自动登录12306自动抢票功能》随着互联网技术的发展,越来越多的人选择通过网络平台购票,特别是在中国,12306作为官方火车票预订平台,承担了巨大的访问量,对于热门线路或者节假日出行... 目录一、遇到的问题?二、改进三、进阶–展望总结一、遇到的问题?1.url-正确的表头:就是首先ur

C#实现文件读写到SQLite数据库

《C#实现文件读写到SQLite数据库》这篇文章主要为大家详细介绍了使用C#将文件读写到SQLite数据库的几种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以参考一下... 目录1. 使用 BLOB 存储文件2. 存储文件路径3. 分块存储文件《文件读写到SQLite数据库China编程的方法》博客中,介绍了文

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Redis主从复制实现原理分析

《Redis主从复制实现原理分析》Redis主从复制通过Sync和CommandPropagate阶段实现数据同步,2.8版本后引入Psync指令,根据复制偏移量进行全量或部分同步,优化了数据传输效率... 目录Redis主DodMIK从复制实现原理实现原理Psync: 2.8版本后总结Redis主从复制实

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主