上次介绍了如何使用JAVA的反射机制来调用蓝牙的隐藏API,这次继续练习JAVA的反射机制,探秘TelephonyManager在Framework里包含却在SDK隐藏的几项功能。先来看看本文程序运行的效果图:
本文程序演示了以下功能:
1.所有来电自动接听;
2.所有来电自动挂断;
3.开启/关闭Radio;
4.开启/关闭数据连接(WAP or NET的连接)。
调用TelephonyManager的隐藏API是先参考Framework的/base/telephony/java/com/android/internal/telephony/ITelephony.aidl,然后自己实现一个ITelephony.aidl,最后在TelephonyManager中通过反射机制实例化自定义的ITelephony,实例化之后就可以调用ITelephony里面的函数了。
本文程序需要在AndroidManifest.xml添加以下两行代码,以获得权限:
1
2
|
< uses-permission android:name = "android.permission.CALL_PHONE" /> < uses-permission android:name = "android.permission.MODIFY_PHONE_STATE" /> |
main.xml源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
<? xml version = "1.0" encoding = "utf-8" ?> android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:orientation = "vertical" > < RadioGroup android:id = "@+id/rGrpSelect" android:layout_width = "fill_parent" android:layout_height = "wrap_content" > < RadioButton android:id = "@+id/rbtnAutoAccept" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "所有来电自动接听" > </ RadioButton > < RadioButton android:id = "@+id/rbtnAutoReject" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "所有来电自动挂断" > </ RadioButton > </ RadioGroup > < ToggleButton android:id = "@+id/tbtnRadioSwitch" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:textOff = "Radio已经关闭" android:textOn = "Radio已经启动" android:textSize = "24dip" android:textStyle = "normal" > </ ToggleButton > < ToggleButton android:id = "@+id/tbtnDataConn" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:textOff = "禁止数据连接" android:textOn = "允许数据连接" android:textSize = "24dip" android:textStyle = "normal" > </ ToggleButton > </ LinearLayout > |
PhoneUtils.java是手机功能类,从TelephonyManager中实例化ITelephony并返回,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.testTelephony; import java.lang.reflect.Field; import java.lang.reflect.Method; import com.android.internal.telephony.ITelephony; import android.telephony.TelephonyManager; import android.util.Log; public class PhoneUtils /** * */ static public ITelephony throws Exception Method "getITelephony" ); getITelephonyMethod.setAccessible( true ); // return (ITelephony) } static public void printAllInform(Class try { // Method[] int i 0 ; for (; Log.e( "method , } // Field[] for (i 0 ; Log.e( "Field , } } catch (SecurityException // e.printStackTrace(); } catch (IllegalArgumentException // e.printStackTrace(); } catch (Exception // e.printStackTrace(); } } } |
testTelephony.java是主类,使用PhoneStateListener监听通话状态,以及实现上述4种电话控制功能,源码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
package com.testTelephony; import android.app.Activity; import android.os.Bundle; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.Log; import android.view.View; import android.widget.RadioGroup; import android.widget.ToggleButton; public class testTelephony extends Activity /** RadioGroup // ToggleButton // ToggleButton // TelephonyManager CallStateListener int checkedId 0 ; @Override public void onCreate(Bundle super .onCreate(savedInstanceState); setContentView(R.layout.main); telMgr telMgr.listen( new CallStateListener(), CallStateListener.LISTEN_CALL_STATE); PhoneUtils.printAllInform(TelephonyManager. class ); rg rg.setOnCheckedChangeListener( new CheckEvent()); tbtnRadioSwitch this .findViewById(R.id.tbtnRadioSwitch); tbtnRadioSwitch.setOnClickListener( new ClickEvent()); try { tbtnRadioSwitch.setChecked(PhoneUtils.getITelephony(telMgr) .isRadioOn()); } catch (Exception Log.e( "error" , } tbtnDataConn this .findViewById(R.id.tbtnDataConn); tbtnDataConn.setOnClickListener( new ClickEvent()); try { tbtnDataConn.setChecked(PhoneUtils.getITelephony(telMgr) .isDataConnectivityPossible()); } catch (Exception Log.e( "error" , } } /** * * * * */ public class CheckEvent implements RadioGroup.OnCheckedChangeListener @Override public void onCheckedChanged(RadioGroup int checkedId) testTelephony. this .checkedId } } /** * * * * */ public class ClickEvent implements View.OnClickListener @Override public void onClick(View if (v try { PhoneUtils.getITelephony(telMgr).setRadio( tbtnRadioSwitch.isChecked()); } catch (Exception Log.e( "error" , } } else if (v try { if (tbtnDataConn.isChecked()) PhoneUtils.getITelephony(telMgr) .enableDataConnectivity(); else if (!tbtnDataConn.isChecked()) PhoneUtils.getITelephony(telMgr) .disableDataConnectivity(); } catch (Exception Log.e( "error" , } } } } /** * * * * */ public class CallStateListener extends PhoneStateListener @Override public void onCallStateChanged( int state, if (state // { Log.e( "IDLE" , } else if (state // { Log.e( "OFFHOOK" , } else if (state // { if (testTelephony. this .checkedId try { // // // PhoneUtils.getITelephony(telMgr).silenceRinger(); // PhoneUtils.getITelephony(telMgr).answerRingingCall(); // } catch (Exception Log.e( "error" , } } else if (testTelephony. this .checkedId try { PhoneUtils.getITelephony(telMgr).endCall(); // PhoneUtils.getITelephony(telMgr) .cancelMissedCallsNotification(); // } catch (Exception Log.e( "error" , } } } super .onCallStateChanged(state, } } } |