Android 系统(125)---Android通过Dialer实现暗码启动 Android通过Dialer实现暗码启动

Android通过Dialer实现暗码启动

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

本文以Dialer为例,

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

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

[java]  view plain  copy
  1. /** 
  2.  * Initiates a fragment transaction to show the dialpad fragment. Animations and other visual 
  3.  * updates are handled by a callback which is invoked after the dialpad fragment is shown. 
  4.  * @see #onDialpadShown 
  5.  */  
  6. private void showDialpadFragment(boolean animate) {  
  7.     if (mIsDialpadShown || mStateSaved) {  
  8.         return;  
  9.     }  
  10.     mIsDialpadShown = true;  
  11.   
  12.     mListsFragment.setUserVisibleHint(false);  
  13.   
  14.     final FragmentTransaction ft = getFragmentManager().beginTransaction();  
  15.     if (mDialpadFragment == null) {  
  16.         mDialpadFragment = new DialpadFragment();  
  17.         ft.add(R.id.dialtacts_container, mDialpadFragment, TAG_DIALPAD_FRAGMENT);  
  18.     } else {  
  19.         ft.show(mDialpadFragment);  
  20.     }  
  21.   
  22.     //mDialpadFragment.setAnimate(animate);  
  23.     AnalyticsUtil.sendScreenView(mDialpadFragment);  
  24.     ft.commit();  
  25.     maybeEnterSearchUi();  
  26.     if (animate) {  
  27.         mFloatingActionButtonController.scaleOut();  
  28.     } else {  
  29.         mFloatingActionButtonController.setVisible(false);  
  30.     }  
  31.     mActionBarController.onDialpadUp();  
  32.   
  33.     mListsFragment.getView().animate().alpha(0).withLayer();  
  34. }  

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


import com.android.dialer.dialpad.DialpadFragment;


[java]  view plain  copy
  1. /** 
  2.  * Fragment that displays a twelve-key phone dialpad. 
  3.  */  
  4. public class DialpadFragment extends Fragment  
  5.         implements View.OnClickListener,  
  6.         View.OnLongClickListener, View.OnKeyListener,  
  7.         AdapterView.OnItemClickListener, TextWatcher,  
  8.         PopupMenu.OnMenuItemClickListener,  
  9.         DialpadKeyButton.OnPressedListener,  
  10.         /// M: add for plug-in @{  
  11.         DialpadExtensionAction {  

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

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


onTextChanged


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


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

[java]  view plain  copy
  1. public static boolean handleChars(Context context, String input, EditText textField) {  
  2.     //get rid of the separators so that the string gets parsed correctly  
  3.     String dialString = PhoneNumberUtils.stripSeparators(input);  
  4.     if (handleDeviceIdDisplay(context, dialString) //*#06#  
  5.             || handleRegulatoryInfoDisplay(context, dialString)  
  6.             || handlePinEntry(context, dialString)  
  7.             || handleAdnEntry(context, dialString, textField)  
  8.             || handleSecretCode(context, dialString) //for the form of *#*#<code>#*#*.  
  9.             /// @}  
  10.             /// M: for plug-in @{  
  11.             || ExtensionManager.getInstance().getDialPadExtension().handleChars(context,  
  12.                     dialString)  
  13.             /// @}  
  14.             ) {  
  15.         return true;  
  16.     }  
  17.     return false;  
  18. }  
5.接下来分开两种讲,一种是直接弹出对话框的那种,类如*#06#,另一种则是调起别的应用等方式。
5.1 )*#*#<code>#*#*

[java]  view plain  copy
  1. /** 
  2.  * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*. 
  3.  * If a secret code is encountered an Intent is started with the android_secret_code://<code> 
  4.  * URI. 
  5.  * 
  6.  * @param context the context to use 
  7.  * @param input the text to check for a secret code in 
  8.  * @return true if a secret code was encountered 
  9.  */  
  10. static boolean handleSecretCode(Context context, String input) {  
  11.     // Secret codes are in the form *#*#<code>#*#*  
  12.   
  13.     /// M: for plug-in @{  
  14.     input = ExtensionManager.getInstance().getDialPadExtension().handleSecretCode(input);  
  15.     /// @}  
  16.   
  17.     int len = input.length();  
  18.     if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {  
  19.         final Intent intent = new Intent(SECRET_CODE_ACTION,  
  20.                 Uri.parse("android_secret_code://" + input.substring(4, len - 4)));///<span style="font-family:Arial, Helvetica, sans-serif;">android_secret_code://287</span>  
  21.         context.sendBroadcast(intent);  
  22.         return true;  
  23.     }  
  24.   
  25.     return false;  
  26. }  
有以上代码可知,最终是通过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

[html]  view plain  copy
  1. <receiver  
  2.     android:name=".EngineerModeReceiver"  
  3.     android:exported="true" >  
  4.     <intent-filter>  
  5.         <action android:name="android.provider.Telephony.SECRET_CODE" />  
  6.         <data  
  7.             android:host="3646633"  
  8.             android:scheme="android_secret_code" />  
  9.     </intent-filter>  
  10. </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

[java]  view plain  copy
  1. // TODO: Use TelephonyCapabilities.getDeviceIdLabel() to get the device id label instead of a  
  2. // hard-coded string.  
  3. static boolean handleDeviceIdDisplay(Context context, String input) {  
  4.     TelephonyManager telephonyManager =  
  5.             (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);  
  6.   
  7.     if (telephonyManager != null && input.equals(MMI_IMEI_DISPLAY)) {  
  8.         int labelResId = (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) ?  
  9.                 R.string.imei : R.string.meid;  
  10.   
  11.         List<String> deviceIds = new ArrayList<String>();  
  12.         if (TelephonyManagerCompat.getPhoneCount(telephonyManager) > 1 &&  
  13.                 CompatUtils.isMethodAvailable(TelephonyManagerCompat.TELEPHONY_MANAGER_CLASS,  
  14.                         "getDeviceId", Integer.TYPE)) {  
  15.             for (int slot = 0; slot < telephonyManager.getPhoneCount(); slot++) {  
  16.                 String deviceId = telephonyManager.getDeviceId(slot);  
  17.                 if (!TextUtils.isEmpty(deviceId)) {  
  18.                     deviceIds.add(deviceId);  
  19.                 }  
  20.             }  
  21.         } else {  
  22.             deviceIds.add(telephonyManager.getDeviceId());  
  23.         }  
  24.   
  25.         AlertDialog alert = new AlertDialog.Builder(context)  
  26.                 .setTitle(labelResId)  
  27.                 .setItems(deviceIds.toArray(new String[deviceIds.size()]), null)  
  28.                 .setPositiveButton(android.R.string.ok, null)  
  29.                 .setCancelable(false)  
  30.                 .show();///直接在Context中弹出对话框,显示IMEI信息  
  31.         return true;  
  32.     }  
  33.     return false;  
  34. }  

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

[java]  view plain  copy
  1. private static boolean handleRegulatoryInfoDisplay(Context context, String input) {  
  2.     if (input.equals(MMI_REGULATORY_INFO_DISPLAY)) {  
  3.         Log.d(TAG, "handleRegulatoryInfoDisplay() sending intent to settings app");  
  4.         Intent showRegInfoIntent = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);  
  5.         try {  
  6.             context.startActivity(showRegInfoIntent);  
  7.         } catch (ActivityNotFoundException e) {  
  8.             Log.e(TAG, "startActivity() failed: " + e);  
  9.         }  
  10.         return true;  
  11.     }  
  12.     return false;  
  13. }  

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

猜你喜欢

转载自blog.csdn.net/zhangbijun1230/article/details/80814070