android系统提供了电话相关的接口供调用,比如获取电话状态,获取手机服务等,也包括获取电话状态。因此可以根据电话状态的不同做不同操作。

本例主要分析一个来电自动接电话的代码,代码是由别人写的,拿来一起学习:

要想监听电话状态,一般的做法是写一个广播接收器监听电话状态的改变,配置文件如下:

<receiver android:name=".AutoAnswerReceiver" android:enabled="true">
        	<intent-filter>
        		<action android:name="android.intent.action.PHONE_STATE" />
        	</intent-filter>
        </receiver>

这个时候如果电话状态改变,比如来电等,就可以进入代码,代码如下:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.media.AudioManager;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.provider.ContactsContract.PhoneLookup;
import android.telephony.TelephonyManager;

public class AutoAnswerReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {

		// 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 a few seconds
			context.startService(new Intent(context, AutoAnswerIntentService.class));
		}		
	}

	// returns -1 if not in contact list, 0 if not starred, 1 if starred
	private int isStarred(Context context, String number) {
		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(new Intent(context, AutoAnswerIntentService.class));

这样就启动了自动接听服务,在这个代码中,使用到了蓝牙接听电话的逻辑,也大概做一介绍:

先看代码如下:

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 picking up 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","Error trying 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); ,其中接电话的这段代码如下:

// Answer the phone
		try {
			answerPhoneAidl(context);
		}
		catch (Exception e) {
			e.printStackTrace();
			Log.d("AutoAnswer","Error trying to answer using telephony service.  Falling back to headset.");
			answerPhoneHeadsethook(context);
		}

先使用一般的aidl方式接听电话,如果出现异常,则模拟一个按键来接听电话,两段代码见下:

private void answerPhoneHeadsethook(Context context) {
		// Simulate a press of the headset button to pick up the call
		Intent buttonDown = new Intent(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 buttonUp instead of buttonDown
		Intent buttonUp = new Intent(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 telephony service (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 extends PreferenceActivity implements OnSharedPreferenceChangeListener 

然后加载xml,用户可以设置很多选项参数。

运行界面见下:

android 自动接听电话 安卓 自动接电话_配置文件


另外,本例中还有一个开机启动类,配置文件见下:

<receiver android:name=".AutoAnswerBootReceiver" android:enabled="true">
        	<intent-filter>
        		<action android:name="android.intent.action.BOOT_COMPLETED" />
        	</intent-filter>
        </receiver>

可以设置notification提示用户

public void onReceive(Context context, Intent intent) {
		AutoAnswerNotifier notifier = new AutoAnswerNotifier(context);
		notifier.updateNotification();
	}



AutoAnswerNotifier主要方法就是可以设置提示或者取消提示:

private void enableNotification() {
		// Intent to call to turn off AutoAnswer
		Intent notificationIntent = new Intent(mContext, AutoAnswerPreferenceActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
		
		// Create the notification
		Notification n = new Notification(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);
	}



最后,别忘记添加权限,因为操作电话等相关服务需要相关权限:

<uses-permission android:name="android.permission.BLUETOOTH" />
	<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
	<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
	<uses-permission android:name="android.permission.READ_CONTACTS" />
	<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />