本文主要讲解Android11手机自动接电话的代码实现。
手机来电时的基本操作过程
一、来电提醒阶段
当有电话呼入时,手机会通过以下方式提醒你:
- 铃声提醒:手机会按照你预先设置的铃声发出声音,铃声的音量大小取决于你之前在手机音量设置选项中的配置。例如,你可以将铃声设置为自己喜欢的歌曲或者系统自带的铃声。一些手机还支持为不同联系人设置专属铃声,这样你一听铃声就能知道来电者是谁。
- 震动提醒(如果开启):除了铃声外,手机还会震动,这种震动强度也可以在手机设置中进行调整。这在嘈杂环境或者你将手机放在口袋、包包里时很有用,能让你及时感知到来电。
- 屏幕显示提醒:手机屏幕会亮起,显示来电号码(如果号码已被识别)或者 “未知号码” 字样,同时还会显示接听和拒接按钮的图标。部分手机还会显示来电者的姓名(如果联系人信息已存储在手机通讯录中)和头像(如果有设置)。
二、接听来电操作
- 滑动接听(大多数智能手机)
在屏幕亮起显示来电信息后,通常可以通过在屏幕上滑动手指来接听电话。例如,在苹果手机上,会有一个 “滑动来接听” 的提示,你需要按照箭头指示的方向滑动屏幕;安卓手机也有类似的操作方式,不过不同品牌和系统版本可能会有所差异,有的是从左向右滑动,有的是向上滑动等。 - 按键接听(部分功能手机或特定场景下的智能手机)
有些手机带有实体按键,比如过去的按键式功能手机,有专门的接听键,一般是绿色的按键,按下这个按键就可以接听电话。在一些带有物理键盘的智能手机中,也可能保留了类似的接听按键设计。
对于一些使用蓝牙耳机或者外接有线耳机的情况,耳机上通常也有接听按钮。当手机有来电时,按下耳机上的接听按钮就可以接听电话,这在双手不方便操作手机时非常方便,比如你在开车或者手上拿着东西的时候。
三、通话阶段
- 使用听筒通话
当你接听电话后,将手机靠近耳朵,声音会通过手机顶部的听筒传出。你可以根据自己的听力情况和周围环境的嘈杂程度,使用手机侧面的音量按键来2. 2. 调整听筒音量大小。 - 使用免提通话
如果想开启免提功能,可以在通话界面中找到免提按钮并点击。开启免提后,手机的声音会通过底部的扬声器播放出来,这样你可以不用将手机放在耳边,方便在双手忙碌时或者多人一起接听电话时使用。例如,你在做饭时双手都是面粉,就可以开启免提通话。 - 切换通话方式(如耳机和听筒切换)
如果在通话过程中插入或者拔出耳机,手机会自动切换通话方式。比如,你本来使用听筒通话,插入耳机后,声音会通过耳机播放;拔出耳机后,又会恢复为听筒通话或者免提通话(如果之前开启了免提)。
四、结束通话操作
- 屏幕操作挂断电话
在通话界面中,一般会有一个红色的 “挂断” 按钮,点击这个按钮就可以结束通话。在一些手机上,可能还支持通过其他手势来挂断电话,比如双击电源键(部分手机支持此功能)。 - 使用实体按键挂断电话(如果有)
对于有实体按键的手机,可能会有一个专门的红色 “挂断” 按键,按下这个按键可以结束通话。 - 耳机操作挂断电话
如果你使用耳机通话,耳机上通常也有挂断按钮,按下这个按钮就可以结束通话。
安卓代码实现自动接听电话
- 添加权限
为了能够监听和控制电话状态,需要在AndroidManifest.xml文件中添加以下权限:
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
- 代码实现
旧版本安卓接听电话代码
使用反射调用answerRingingCall函数
public void acceptCall() {
try {
Method method = Class.forName("android.os.ServiceManager")
.getMethod("getService", String.class);
IBinder binder = (IBinder) method.invoke(null, new Object[]{Context.TELEPHONY_SERVICE});
ITelephony telephony = ITelephony.Stub.asInterface(binder);
telephony.answerRingingCall();
} catch (NoSuchMethodException e) {
Log.d(TAG, "", e);
} catch (ClassNotFoundException e) {
Log.d(TAG, "", e);
} catch (Exception e) {
Log.d(TAG, "", e);
}
}
在新版本安卓中,以上方法无法使用,查看安卓SDK代码frameworks下代码会发现answerRingingCall函数已经失效了,被acceptRingingCall替代了,
frameworks/base/telephony/java/android/telephony/TelephonyManager.java
/**
* @removed Use {@link android.telecom.TelecomManager#acceptRingingCall} instead
* @hide
* @removed
*/
@Deprecated
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void answerRingingCall() {
// No-op
}
新版本接听电话实现,Android11中实测
private PhoneReceiver mPhoneReceiver;
mPhoneReceiver = new PhoneReceiver();
registerReceiver(mPhoneReceiver, new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL));
registerReceiver(mPhoneReceiver, new IntentFilter("android.intent.action.PHONE_STATE"));
public class PhoneReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.intent.action.PHONE_STATE")) {
// 来电了
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:
// 响铃了
String incoming_number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Log.d(TAG, "来电手机号:" + incoming_number);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
acceptRingingCall();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// 通话中
break;
case TelephonyManager.CALL_STATE_IDLE:
// 空闲状态,即没有电话活动
break;
default:
break;
}
} else if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
// 处理拨打电话事件
}
}
}
// 接听电话
public void acceptRingingCall() {
// 检查权限
final int PERMISSION_REQUEST_CODE = 1;
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, PERMISSION_REQUEST_CODE);
return;
}
// 反射接听电话
TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
try {
Method method = telecomManager.getClass().getDeclaredMethod("acceptRingingCall");
method.invoke(telecomManager);
} catch (Exception e) {
e.printStackTrace();
}
/*
// 非反射接听电话
TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);
if (telecomManager != null) {
try {
telecomManager.acceptRingingCall();
} catch (SecurityException e) {
// 没有权限或者没有默认电话应用的异常处理
}
}
*/
}
自动接听后,手机界面上还会处于来电等待接听的界面,可以再在最上层弄个UI遮挡住它,最优的做法是在framework代码层对电话进行接听及UI变化的处理,这里不再详述。
作者:帅得不敢出门