在Android中以编程方式结束通话

37

我看到很多问题说在安卓系统中不能编程结束通话。与此同时,我在谷歌应用商店里看到许多拨号应用程序可以激活通话并挂断。它们是如何工作的?

编辑: 我在某个地方读到我的应用程序必须成为系统应用程序。那么如何将其变成系统应用程序,系统应用程序和用户应用程序有什么区别?


3
对于我来说,有更好的解决方案可以实现这一点。 - bgplaya
请参考 http://android.stackexchange.com/q/27/440 了解如何将应用程序变成系统应用的指南。 - Flow
1
请查看以下答案: https://dev59.com/q1YN5IYBdhLWcg3wQWIV#57356900 - Gaurav Agrawal
9个回答

51

您不需要成为系统应用程序。首先,在您的项目中创建包com.android.internal.telephony,并将其放入名为"ITelephony.aidl"的文件中:

package com.android.internal.telephony; 

interface ITelephony {      

boolean endCall();     

void answerRingingCall();      

void silenceRinger(); 

}

一旦你获得了那个,就可以使用这段代码来结束通话:

TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class clazz = Class.forName(telephonyManager.getClass().getName());
Method method = clazz.getDeclaredMethod("getITelephony");
method.setAccessible(true);
ITelephony telephonyService = (ITelephony) method.invoke(telephonyManager);
telephonyService.endCall();

例如,您可以在PhoneStateListener中使用它。为了使其工作,您需要在清单文件中添加权限:

<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

编辑:很抱歉格式不好看,我还是搞不清楚如何在这里正确地使用代码块 :/


<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" /> 无法使用,如果没有上述权限,则无法在运行时访问TelephonyManager。 - VenomVendor
1
@VenomVendor 我记得在调试时在logcat中收到了一个警告,大致是“未授予权限MODIFY_PHONE_STATE”,但似乎并不是问题,因为上述代码在各种设备上都能正常工作。也许这个权限实际上并不是必要的? - bgse
1
@MAHANTESH 这个特定的项目是使用minSdkVersion ="8"和targetSdkVersion ="15"构建的。我刚刚重新检查确认了一下,它可以编译并且无任何问题地部署。当应用程序被执行时,它会在logcat中产生一个警告“Not granting permission MODIFY_PHONE_STATE”。然而,那似乎并不影响任何功能,所以我猜这个权限并不是真正需要的。你是在编译时还是运行时遇到错误? - bgse
3
仅当minSdkVersion为14或更低版本时,此功能才有效。如果将minSdkVersion设置为15或更高版本,则该功能将停止工作。 - Bjarte Aune Olsen
3
这段代码曾在2013年起作用,它的基本作用是使用反射(reflection)来获得Android电话内部功能的访问权限,否则这些功能在公开情况下无法访问。由于很多内部结构在2013年以后发生了变化,所以几乎可以确定这段代码不再起作用了(至少不会像这里展示的那样)。我大概记得Android 4.0.3还可以工作,但对于之后的版本就不太确定了。 - bgse
显示剩余12条评论

22

针对 Android P(Beta 2及以上版本),终于推出了一个正式 API,用于结束通话:

https://developer.android.com/reference/android/telecom/TelecomManager#endCall()

在清单文件中需要声明ANSWER_PHONE_CALLS 权限:

<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />

在获得权限的情况下,适用于API级别28或更高:

TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);

if (tm != null) {
    boolean success = tm.endCall();
    // success == true if call was terminated.
}

同时原来在TelephonyManager下的endCall()方法现在被MODIFY_PHONE_STATE权限保护,非系统应用程序在没有该权限的情况下无法通过反射调用该方法(否则将触发安全异常)。


你提供了非常有用的信息,但在Oreo中如何处理呢?因为我找不到endcall方法。 - Panache
@Panache请查看有关在TelephonyManager中访问隐藏的endcall方法的Oreo或之前的已接受答案。 - headuck
1
我得到了“无法解析endCall方法”的错误,我已经安装了API 28,有什么提示吗? - David
2
它已在API级别29中正式弃用。 - Chintan Desai
建议使用 https://developer.android.com/reference/android/telecom/CallScreeningService.html。但是无法找到如何通过呼叫筛选服务结束通话的方法。 - Sagar Nayak
显示剩余4条评论

3

关于信息。

在某些情况下可能会有用。使用InCallService类可以有一个潜在的解决方法。大部分所需信息都在这里。https://developer.android.com/reference/android/telecom/InCallService.html#onCallRemoved(android.telecom.Call)

它需要将您的应用程序设置为默认电话应用程序,并确保授予以下权限。

<uses-permission android:name="android.permission.CALL_PHONE" />

如果你实现自己的类扩展 InCallService,那么当一个电话开始时,该电话会绑定到你的应用程序上,并通过 onCallAdded() 函数获取呼叫信息。然后你可以简单地调用 call.disconnect() 来结束通话。


1
重要提示:要使用ICallService,您需要从设置中将您的应用程序设置为默认电话应用程序。这意味着,当您有来电时,其他应用程序将无法控制,并且您必须在您的应用程序中处理所有通话功能。 - Pankaj
我一直在寻找不同的解决方案,但都没有奏效,最终发现了这个。如此简单而又实用。谢谢。 - Saify

2

削减API 28+的调用

private void cutCall(){
    ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_PHONE_STATE }, PHONE_STATE);
}

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == PHONE_STATE) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ANSWER_PHONE_CALLS }, ANSWER_CALLS);
        } else if (requestCode == ANSWER_CALLS) {
            cutTheCall;
        }
    }
}

//这段代码适用于Android N(Api 28及以上)

private boolean cutTheCall() {
    TelecomManager telecomManager = (TelecomManager) getApplicationContext().getSystemService(TELECOM_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || telecomManager == null) {
        return false;
    }

    if (telecomManager.isInCall()) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            callDisconnected = telecomManager.endCall();
        }
    }
    return true;
}

此代码需要API版本在26及以上。请确保在您的清单文件中添加以下内容:<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />。 - iqbalzas

1

SilenceRinger() 在 Android 2.3+ 版本中不起作用。只需将其注释掉,其他代码将正常工作。 希望这对你有用!


1
除了添加Android电话接口和广播接收器外,您还需要添加Android清单接收器条目,并使用操作android.intent.action.PHONE_STATE为要处理意图的接收器添加条目。
如果您添加了以下内容,将会出现编译时错误。
uses-permission android:name="android.permission.MODIFY_PHONE_STATE`

在您的清单文件中。但即使我们删除它,它也会自动拒绝来电。


1
使用以下方式<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" tools:ignore="ProtectedPermissions" />,以避免编译或任何其他错误。 - AshuKingSharma

0

只是为了补充@headuck的答案。对于API 28,您还需要添加:

<uses-permission android:name="android.permission.READ_CALL_LOG"/>

然后在您的活动中请求权限。总共我请求了这些权限来使它工作(READ_PHONE_STATE,CALL_PHONE,ANSWER_PHONE_CALLS,READ_CONTACTS,READ_CALL_LOG)


0
public static boolean isCallActive(Context context){
    AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    if(manager.getMode()==AudioManager.MODE_IN_CALL || manager.getMode()==AudioManager.MODE_IN_COMMUNICATION){
        return true;
    }

    return false;
}

-1

您可以使用电信管理器来结束通话。我进行了测试,它可以正常工作。 您需要获得 ANSWER_PHONE_CALLS 权限才能这样做。尽管它提示已接听的通话,但我已经成功地结束了从此手机拨出的通话。而且这适用于现代 Android 手机。

   TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);

telecomManager.endCall();


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接