android系统提供了电话相关的接口供调用,比如获取电话状态,获取手机服务等,也包括获取电话状态。因此可以根据电话状态的不同做不同操作。
本例主要分析一个来电自动接电话的代码,代码是由别人写的,拿来一起学习:
要想监听电话状态,一般的做法是写一个广播接收器监听电话状态的改变,配置文件如下:
[java] view plaincopyprint?
1. <receiver android:name=".AutoAnswerReceiver" android:enabled="true">
2. <intent-filter>
3. <action android:name="android.intent.action.PHONE_STATE" />
4. </intent-filter>
5. </receiver>
<receiverandroid:name=".AutoAnswerReceiver"android:enabled="true">
<intent-filter>
<actionandroid:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
这个时候如果电话状态改变,比如来电等,就可以进入代码,代码如下:
[java] view plaincopyprint?
1. import android.content.BroadcastReceiver;
2. import android.content.Context;
3. import android.content.Intent;
4. import android.content.SharedPreferences;
5. import android.database.Cursor;
6. import android.media.AudioManager;
7. import android.net.Uri;
8. import android.preference.PreferenceManager;
9. import android.provider.ContactsContract.PhoneLookup;
10.import android.telephony.TelephonyManager;
11.
12.public class AutoAnswerReceiver extends BroadcastReceiver {
13. @Override
14. public void onReceive(Context context, Intent intent) {
15.
16. // Load preferences
17. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
18.
19. // Check phone state
20. String phone_state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
21. String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
22.
23. if (phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING) && prefs.getBoolean("enabled", false)) {
24. // Check for "second call" restriction
25. if (prefs.getBoolean("no_second_call", false)) {
26. AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
27. if (am.getMode() == AudioManager.MODE_IN_CALL) {
28. return;
29. }
30. }
31.
32. // Check for contact restrictions
33. String which_contacts = prefs.getString("which_contacts", "all");
34. if (!which_contacts.equals("all")) {
35. int is_starred = isStarred(context, number);
36. if (which_contacts.equals("contacts") && is_starred < 0) {
37. return;
38. }
39. else if (which_contacts.equals("starred") && is_starred < 1) {
40. return;
41. }
42. }
43.
44. // Call a service, since this could take a few seconds
45. context.startService(new Intent(context, AutoAnswerIntentService.class));
46. }
47. }
48.
49. // returns -1 if not in contact list, 0 if not starred, 1 if starred
50. private int isStarred(Context context, String number) {
51. int starred = -1;
52. Cursor c = context.getContentResolver().query(
53. Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
54. new String[] {PhoneLookup.STARRED},
55. null, null, null);
56. if (c != null) {
57. if (c.moveToFirst()) {
58. starred = c.getInt(0);
59. }
60. c.close();
61. }
62. return starred;
63. }
64.}
importandroid.content.BroadcastReceiver;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.SharedPreferences;
importandroid.database.Cursor;
importandroid.media.AudioManager;
importandroid.net.Uri;
importandroid.preference.PreferenceManager;
importandroid.provider.ContactsContract.PhoneLookup;
importandroid.telephony.TelephonyManager;
publicclass AutoAnswerReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intentintent) {
// Load preferences
SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferences(context);
// Check phone state
String phone_state =intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String number =intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if(phone_state.equals(TelephonyManager.EXTRA_STATE_RINGING) &&prefs.getBoolean("enabled", false)) {
// Check for "second call"restriction
if (prefs.getBoolean("no_second_call",false)) {
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
if (am.getMode() ==AudioManager.MODE_IN_CALL) {
return;
}
}
// Check for contact restrictions
String which_contacts = prefs.getString("which_contacts","all");
if(!which_contacts.equals("all")) {
int is_starred = isStarred(context,number);
if(which_contacts.equals("contacts") && is_starred < 0) {
return;
}
else if(which_contacts.equals("starred") && is_starred < 1) {
return;
}
}
// Call a service, since this could take afew seconds
context.startService(new Intent(context,AutoAnswerIntentService.class));
}
}
// returns -1 if not in contact list, 0 if notstarred, 1 if starred
private int isStarred(Context context, Stringnumber) {
int starred = -1;
Cursor c =context.getContentResolver().query(
Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,number),
new String[] {PhoneLookup.STARRED},
null, null, null);
if (c != null) {
if (c.moveToFirst()) {
starred = c.getInt(0);
}
c.close();
}
return starred;
}
}
暂且不管其他代码,因为其他的代码主要是对设置选项分别作判断,如果电话状态改变,则启动自动接听服务,即:context.startService(newIntent(context, AutoAnswerIntentService.class));
这样就启动了自动接听服务,在这个代码中,使用到了蓝牙接听电话的逻辑,也大概做一介绍:
先看代码如下:
[java] view plaincopyprint?
1. protected void onHandleIntent(Intent intent) {
2. Context context = getBaseContext();
3.
4. // Load preferences
5. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
6. BluetoothHeadset bh = null;
7. if (prefs.getBoolean("headset_only", false)) {
8. bh = new BluetoothHeadset(this, null);
9. }
10.
11. // Let the phone ring for a set delay
12. try {
13. Thread.sleep(Integer.parseInt(prefs.getString("delay", "2")) * 1000);
14. } catch (InterruptedException e) {
15. // We don't really care
16. }
17.
18. // Check headset status right before picking up the call
19. if (prefs.getBoolean("headset_only", false) && bh != null) {
20. if (bh.getState() != BluetoothHeadset.STATE_CONNECTED) {
21. bh.close();
22. return;
23. }
24. bh.close();
25. }
26.
27. // Make sure the phone is still ringing
28. TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
29. if (tm.getCallState() != TelephonyManager.CALL_STATE_RINGING) {
30. return;
31. }
32.
33. // Answer the phone
34. try {
35. answerPhoneAidl(context);
36. }
37. catch (Exception e) {
38. e.printStackTrace();
39. Log.d("AutoAnswer","Error trying to answer using telephony service. Falling back to headset.");
40. answerPhoneHeadsethook(context);
41. }
42.
43. // Enable the speakerphone
44. if (prefs.getBoolean("use_speakerphone", false)) {
45. enableSpeakerPhone(context);
46. }
47. return;
48.}
protected void onHandleIntent(Intent intent) {
Context context = getBaseContext();
// Load preferences
SharedPreferences prefs =PreferenceManager.getDefaultSharedPreferences(context);
BluetoothHeadset bh = null;
if(prefs.getBoolean("headset_only", false)) {
bh = new BluetoothHeadset(this, null);
}
// Let the phone ring for a set delay
try {
Thread.sleep(Integer.parseInt(prefs.getString("delay","2")) * 1000);
} catch (InterruptedException e) {
// We don't really care
}
// Check headset status right before pickingup the call
if(prefs.getBoolean("headset_only", false) && bh != null) {
if (bh.getState() !=BluetoothHeadset.STATE_CONNECTED) {
bh.close();
return;
}
bh.close();
}
// Make sure the phone is still ringing
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (tm.getCallState() !=TelephonyManager.CALL_STATE_RINGING) {
return;
}
// Answer the phone
try {
answerPhoneAidl(context);
}
catch (Exception e) {
e.printStackTrace();
Log.d("AutoAnswer","Errortrying to answer using telephony service. Falling back to headset.");
answerPhoneHeadsethook(context);
}
// Enable the speakerphone
if(prefs.getBoolean("use_speakerphone", false)) {
enableSpeakerPhone(context);
}
return;
}
先判断是否设置为蓝牙耳机接电话,如果不是则使用普通方式接听,当然先确保此时电话还在响铃,因为有时候电话也可能只响一声。然后就自动接电话,见answerPhoneAidl(context); ,其中接电话的这段代码如下:
[java] view plaincopyprint?
1. // Answer the phone
2. try {
3. answerPhoneAidl(context);
4. }
5. catch (Exception e) {
6. e.printStackTrace();
7. Log.d("AutoAnswer","Error trying to answer using telephony service. Falling back to headset.");
8. answerPhoneHeadsethook(context);
9. }
// Answer the phone
try {
answerPhoneAidl(context);
}
catch (Exception e) {
e.printStackTrace();
Log.d("AutoAnswer","Errortrying to answer using telephony service. Falling back to headset.");
answerPhoneHeadsethook(context);
}
先使用一般的aidl方式接听电话,如果出现异常,则模拟一个按键来接听电话,两段代码见下:
[java] view plaincopyprint?
1. private void answerPhoneHeadsethook(Context context) {
2. // Simulate a press of the headset button to pick up the call
3. Intent buttonDown = new Intent(Intent.ACTION_MEDIA_BUTTON);
4. buttonDown.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
5. context.sendOrderedBroadcast(buttonDown, "android.permission.CALL_PRIVILEGED");
6.
7. // froyo and beyond trigger on buttonUp instead of buttonDown
8. Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);
9. buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
10. context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
11.}
12.
13.@SuppressWarnings("unchecked")
14.private void answerPhoneAidl(Context context) throws Exception {
15. // Set up communication with the telephony service (thanks to Tedd's Droid Tools!)
16. TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
17. Class c = Class.forName(tm.getClass().getName());
18. Method m = c.getDeclaredMethod("getITelephony");
19. m.setAccessible(true);
20. ITelephony telephonyService;
21. telephonyService = (ITelephony)m.invoke(tm);
22.
23. // Silence the ringer and answer the call!
24. telephonyService.silenceRinger();
25. telephonyService.answerRingingCall();
26.}
private void answerPhoneHeadsethook(Contextcontext) {
// Simulate a press of the headset button topick up the call
Intent buttonDown = newIntent(Intent.ACTION_MEDIA_BUTTON);
buttonDown.putExtra(Intent.EXTRA_KEY_EVENT,new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(buttonDown,"android.permission.CALL_PRIVILEGED");
// froyo and beyond trigger on buttonUpinstead of buttonDown
Intent buttonUp = newIntent(Intent.ACTION_MEDIA_BUTTON);
buttonUp.putExtra(Intent.EXTRA_KEY_EVENT,new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(buttonUp,"android.permission.CALL_PRIVILEGED");
}
@SuppressWarnings("unchecked")
private void answerPhoneAidl(Context context)throws Exception {
// Set up communication with the telephonyservice (thanks to Tedd's Droid Tools!)
TelephonyManager tm = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
Class c =Class.forName(tm.getClass().getName());
Method m =c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
ITelephony telephonyService;
telephonyService = (ITelephony)m.invoke(tm);
// Silence the ringer and answer the call!
telephonyService.silenceRinger();
telephonyService.answerRingingCall();
}
一般由上述代码就可以接电话了,或许在某些手机上,如果本身更改了framework代码实现,可能会接不起来,需要另作修改。
本文开始提到的设置选项就是该应用启动界面,是用PreferenceActivity写的,见下:
public class AutoAnswerPreferenceActivity extendsPreferenceActivity implements OnSharedPreferenceChangeListener
然后加载xml,用户可以设置很多选项参数。
运行界面见下:
另外,本例中还有一个开机启动类,配置文件见下:
[java] view plaincopyprint?
1. <receiver android:name=".AutoAnswerBootReceiver" android:enabled="true">
2. <intent-filter>
3. <action android:name="android.intent.action.BOOT_COMPLETED" />
4. </intent-filter>
5. </receiver>
<receiverandroid:name=".AutoAnswerBootReceiver"android:enabled="true">
<intent-filter>
<actionandroid:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
可以设置notification提示用户
[java] view plaincopyprint?
1. public void onReceive(Context context, Intent intent) {
2. AutoAnswerNotifier notifier = new AutoAnswerNotifier(context);
3. notifier.updateNotification();
4. }
public void onReceive(Context context, Intentintent) {
AutoAnswerNotifier notifier = newAutoAnswerNotifier(context);
notifier.updateNotification();
}
AutoAnswerNotifier主要方法就是可以设置提示或者取消提示:
[java] view plaincopyprint?
1. private void enableNotification() {
2. // Intent to call to turn off AutoAnswer
3. Intent notificationIntent = new Intent(mContext, AutoAnswerPreferenceActivity.class);
4. PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
5.
6. // Create the notification
7. Notification n = new Notification(R.drawable.stat_sys_autoanswer, null, 0);
8. n.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
9. n.setLatestEventInfo(mContext, mContext.getString(R.string.notification_title), mContext.getString(R.string.notification_text), pendingIntent);
10. mNotificationManager.notify(NOTIFICATION_ID, n);
11.}
12.
13.private void disableNotification() {
14. mNotificationManager.cancel(NOTIFICATION_ID);
15.}
private void enableNotification() {
// Intent to call to turn off AutoAnswer
Intent notificationIntent = newIntent(mContext, AutoAnswerPreferenceActivity.class);
PendingIntent pendingIntent =PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
// Create the notification
Notification n = newNotification(R.drawable.stat_sys_autoanswer, null, 0);
n.flags |= Notification.FLAG_ONGOING_EVENT |Notification.FLAG_NO_CLEAR;
n.setLatestEventInfo(mContext,mContext.getString(R.string.notification_title),mContext.getString(R.string.notification_text), pendingIntent);
mNotificationManager.notify(NOTIFICATION_ID,n);
}
private void disableNotification() {
mNotificationManager.cancel(NOTIFICATION_ID);
}
最后,别忘记添加权限,因为操作电话等相关服务需要相关权限:
[java] view plaincopyprint?
1. <uses-permission android:name="android.permission.BLUETOOTH" />
2. <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
3. <uses-permission android:name="android.permission.READ_PHONE_STATE" />
4. <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
5. <uses-permission android:name="android.permission.READ_CONTACTS" />
6. <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permissionandroid:name="android.permission.BLUETOOTH" />
<uses-permissionandroid:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permissionandroid:name="android.permission.READ_PHONE_STATE" />
<uses-permissionandroid:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permissionandroid:name="android.permission.RECEIVE_BOOT_COMPLETED" />
本例代码会一并上传供下载学习,链接如下:
http://download.csdn.net/detail/bawang_cn/5031509
come from:http://blog.csdn.net/bawang_cn/article/details/8545043