如何挂断 Android 中的拨出电话?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/599443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:19:31  来源:igfitidea点击:

How to hang up outgoing call in Android?

androidtelephonytelephonymanager

提问by Tilek

I am developing an application where one of the things we need is to control the outgoing call, at least to be able to stop it from our application.

我正在开发一个应用程序,其中我们需要做的一件事是控制传出呼叫,至少能够从我们的应用程序中阻止它。

I've tried using Intent.ACTION_CALLfrom an existing activity:

我尝试Intent.ACTION_CALL从现有活动中使用:

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber)); 
startActivity(callIntent); 

But stopping the call seems to be disallowed through the API.

但是似乎不允许通过 API 停止调用。

Can you suggest some workaround?

你能提出一些解决方法吗?

For example: enabling airplane mode during the call? Just an example; this hack didn't work for me.

例如:通话时开启飞行模式?只是一个例子;这个 hack 对我不起作用。

回答by Paul Lammertsma

Capturing the outgoing call in a BroadcastReceiverhas been mentioned and is definitely the best way to do it if you want to end the call before dialing.

BroadcastReceiver已经提到在 a 中捕获拨出电话,如果您想在拨号前结束通话,这绝对是最好的方法。

Once dialing or in-call, however, that technique no longer works. The only way to hang up that I've encountered so far, is to do so through Java Reflection. As it is not part of the public API, you should be careful to use it, and not rely upon it. Any change to the internal composition of Android will effectively break your application.

然而,一旦拨号或通话,该技术就不再有效。到目前为止,我遇到的唯一挂断方法是通过 Java Reflection挂断。由于它不是公共 API 的一部分,因此您应该小心使用它,而不是依赖它。对 Android 内部组成的任何更改都会有效地破坏您的应用程序。

Prasanta Paul's blog demonstrateshow it can be accomplished, which I have summarized below.

Prasanta Paul 的博客展示了它是如何实现的,我总结如下。

Obtaining the ITelephonyobject:

获取ITelephony对象:

TelephonyManager tm = (TelephonyManager) context
        .getSystemService(Context.TELEPHONY_SERVICE);
try {
    // Java reflection to gain access to TelephonyManager's
    // ITelephony getter
    Log.v(TAG, "Get getTeleService...");
    Class c = Class.forName(tm.getClass().getName());
    Method m = c.getDeclaredMethod("getITelephony");
    m.setAccessible(true);
    com.android.internal.telephony.ITelephony telephonyService =
            (ITelephony) m.invoke(tm);
} catch (Exception e) {
    e.printStackTrace();
    Log.e(TAG,
            "FATAL ERROR: could not connect to telephony subsystem");
    Log.e(TAG, "Exception object: " + e);
}

Ending the call:

结束通话:

telephonyService.endCall();

回答by Felipe

EDIT:To Android P or newer, please see: https://stackoverflow.com/a/51121175/450148

编辑:对于 Android P 或更新版本,请参阅:https: //stackoverflow.com/a/51121175/450148

Try this:

尝试这个:

(I used Reflection to access advanced telephony featuresand modify somethings)

(我使用反射来访问高级电话功能并修改一些东西)

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

try {
    //String serviceManagerName = "android.os.IServiceManager";
    String serviceManagerName = "android.os.ServiceManager";
    String serviceManagerNativeName = "android.os.ServiceManagerNative";
    String telephonyName = "com.android.internal.telephony.ITelephony";

    Class telephonyClass;
    Class telephonyStubClass;
    Class serviceManagerClass;
    Class serviceManagerStubClass;
    Class serviceManagerNativeClass;
    Class serviceManagerNativeStubClass;

    Method telephonyCall;
    Method telephonyEndCall;
    Method telephonyAnswerCall;
    Method getDefault;

    Method[] temps;
    Constructor[] serviceManagerConstructor;

    // Method getService;
    Object telephonyObject;
    Object serviceManagerObject;

    telephonyClass = Class.forName(telephonyName);
    telephonyStubClass = telephonyClass.getClasses()[0];
    serviceManagerClass = Class.forName(serviceManagerName);
    serviceManagerNativeClass = Class.forName(serviceManagerNativeName);

    Method getService = // getDefaults[29];
    serviceManagerClass.getMethod("getService", String.class);

    Method tempInterfaceMethod = serviceManagerNativeClass.getMethod(
                "asInterface", IBinder.class);

    Binder tmpBinder = new Binder();
    tmpBinder.attachInterface(null, "fake");

    serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
    IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
    Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);

    telephonyObject = serviceMethod.invoke(null, retbinder);
    //telephonyCall = telephonyClass.getMethod("call", String.class);
    telephonyEndCall = telephonyClass.getMethod("endCall");
    //telephonyAnswerCall = telephonyClass.getMethod("answerRingingCall");

    telephonyEndCall.invoke(telephonyObject);

} catch (Exception e) {
    e.printStackTrace();
    Log.error(DialerActivity.this,
                "FATAL ERROR: could not connect to telephony subsystem");
    Log.error(DialerActivity.this, "Exception object: " + e);
}

回答by Felipe

  1. Create a BroadcastReceiverwith a priority of 0.
  2. In the BC intercept the ACTION_NEW_OUTGOING_CALLintent in its onReceivemethod
  3. call setResultData(null)in the same method
  1. 创建BroadcastReceiver优先级为 0 的 a。
  2. 在 BC 中拦截ACTION_NEW_OUTGOING_CALLonReceive方法中的意图
  3. 调用setResultData(null)相同的方法

This will prevent the call from initiating (as long as your receiver is the last to process the intent I think)

这将阻止呼叫发起(只要您的接收者是我认为最后一个处理意图的人)

回答by android developer

Here's the most updated code, which will work for Android P too, because it has an official API for it (here) :

这是最新的代码,它也适用于 Android P,因为它有一个官方 API(这里):

in manifest, add this:

在清单中,添加以下内容:

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

In code, use this:

在代码中,使用这个:

Java:

爪哇:

@SuppressLint("PrivateApi")
public static boolean endCall(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        final TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
        if (telecomManager != null && ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
            telecomManager.endCall();
            return true;
        }
        return false;
    }
    //use unofficial API for older Android versions, as written here: https://stackoverflow.com/a/8380418/878126
    try {
        final Class<?> telephonyClass = Class.forName("com.android.internal.telephony.ITelephony");
        final Class<?> telephonyStubClass = telephonyClass.getClasses()[0];
        final Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
        final Class<?> serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative");
        final Method getService = serviceManagerClass.getMethod("getService", String.class);
        final Method tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder.class);
        final Binder tmpBinder = new Binder();
        tmpBinder.attachInterface(null, "fake");
        final Object serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
        final IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
        final Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);
        final Object telephonyObject = serviceMethod.invoke(null, retbinder);
        final Method telephonyEndCall = telephonyClass.getMethod("endCall");
        telephonyEndCall.invoke(telephonyObject);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        LogManager.e(e);
    }
    return false;
}

or in Kotlin:

或在科特林:

@SuppressLint("PrivateApi")
fun endCall(context: Context): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
            telecomManager.endCall()
            return true
        }
        return false
    }
    //use unofficial API for older Android versions, as written here: https://stackoverflow.com/a/8380418/878126
    try {
        val telephonyClass = Class.forName("com.android.internal.telephony.ITelephony")
        val telephonyStubClass = telephonyClass.classes[0]
        val serviceManagerClass = Class.forName("android.os.ServiceManager")
        val serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative")
        val getService = serviceManagerClass.getMethod("getService", String::class.java)
        val tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder::class.java)
        val tmpBinder = Binder()
        tmpBinder.attachInterface(null, "fake")
        val serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder)
        val retbinder = getService.invoke(serviceManagerObject, "phone") as IBinder
        val serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder::class.java)
        val telephonyObject = serviceMethod.invoke(null, retbinder)
        val telephonyEndCall = telephonyClass.getMethod("endCall")
        telephonyEndCall.invoke(telephonyObject)
        return true
    } catch (e: Exception) {
        e.printStackTrace()
        return false
    }
}

回答by Gung Shi Jie

You can try enabling then disabling airplane mode:

您可以尝试启用然后禁用飞行模式:

android.provider.Settings.System.putInt(getContentResolver(),
        android.provider.Settings.System.AIRPLANE_MODE_ON, 1);

Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 1);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);
android.provider.Settings.System.putInt(getContentResolver(),
        android.provider.Settings.System.AIRPLANE_MODE_ON, 0);

intent.putExtra("state", 0);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);

回答by Tony

For Ilana:

对于伊拉娜:

public class ilanasReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            if (getResultData()!=null) {
                String number = "123456";
                setResultData(number);
            }
        }
    }
}

In addition in Manifest put in package section:

另外在 Manifest 中放入 package 部分:

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

That is all.

就这些。

回答by Pat

Considering the potential for wonderful mischief I would be surprised if this is allowed.

考虑到可能会发生奇妙的恶作剧,如果允许的话,我会感到惊讶。

This thread says flatly that the API cannot end a call. Others have tried.

这个线程断然说API 不能结束调用。其他人已经尝试过

回答by Denis Souza

According to the documentation on ACTION_NEW_OUTGOING_CALL

根据 ACTION_NEW_OUTGOING_CALL 上的文档

The Intent will have the following extra value:

EXTRA_PHONE_NUMBER - the phone number originally intended to be dialed.

Once the broadcast is finished, the resultData is used as the actual number to call. If null, no call will be placed.

意图将具有以下额外价值:

EXTRA_PHONE_NUMBER - 最初打算拨打的电话号码。

广播完成后,resultData 将用作要调用的实际号码。如果为空,则不会发出呼叫。