如何在安卓手机上自动且程序化地接听来电

3
我正尝试在我的应用程序中检测到来电并自动应答。我的应用程序已经可以检测到我有一个来电,但仍然不能自动接听电话。我正在使用telephonyManager,并已阅读了这篇教程Answer incoming call using android.telecom and InCallService、这篇Answer Incoming Call in Android 6.0和这篇Can't answer incoming call in android marshmallow 6.0。如果有人知道如何做到这一点,请告诉我。我不介意更改我的代码,我只想让它做完,这是我的代码。
这是我检测到来电并尝试自动接听的类。
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.telecom.Log;
    import android.telephony.TelephonyManager;
    import android.view.KeyEvent;
    import android.widget.Toast;

    import java.io.IOException;

public class InterceptCall extends BroadcastReceiver {



    @Override
    public void onReceive(final Context context, Intent intent) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);

        try {
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)){
                Toast.makeText(context, "Ringing!!", Toast.LENGTH_SHORT).show();
                TelephonyMethods.AnswerRinginCall(telephonyManager);//method that should answer incoming calls 

            }
            if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)){
                Toast.makeText(context, "Received!!", Toast.LENGTH_SHORT).show();
            }
            if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)){
                Toast.makeText(context, "IDL!!", Toast.LENGTH_SHORT).show();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

}

我需要调用telephonyManager类的answerRingingCall()方法的类

public class TelephonyMethods {

    public static void AnswerRinginCall(final TelephonyManager manager){
           manager.answerRingingCall();
    }


}

telephonyManager类的方法

 /** @hide */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
    public void answerRingingCall() {
        try {
            ITelephony telephony = getITelephony();
            if (telephony != null)
                telephony.answerRingingCall();
        } catch (RemoteException e) {
            Log.e(TAG, "Error calling ITelephony#answerRingingCall", e);
        }
    }

Android 6.0你需要处理运行时权限。 - sasikumar
这是我使用的,因为那些我曾经失败的时候。 - Juan Antonio Sánchez Jiménez
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> <uses-permission android:name="android.permission.CALL_PHONE"></uses-permission> <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"></uses-permission> <uses-permission android:name="android.permission.ACCESS_SUPERUSER"/> <uses-permission android:name="android.permission.ACCEPT_HANDOVER"></uses-permission> - Juan Antonio Sánchez Jiménez
<receiver android:name="InterceptCall"> <intent-filter> <action android:name="android.intent.action.PHONE_STATE"></action> </intent-filter> </receiver> - Juan Antonio Sánchez Jiménez
请参考以下链接:https://dev59.com/J1wX5IYBdhLWcg3w-Thv。 - sasikumar
显示剩余2条评论
1个回答

3

我正在处理同样的需求,现在将整个类分享出来,该类适用于所有API版本且表现良好。

public class CallManager {
    private static final String TAG = CallManager.class.getSimpleName();
    private AudioManager audioManager;
    private Context context;

    public CallManager(Context context) {
        this.context = context;
        audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
    }

    public void acceptCall() {
        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
                if (telecomManager != null) {
                    telecomManager.acceptRingingCall();
                }
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                throughMediaController(context);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                throughAudioManager();
            }
        } catch (Exception e) {
            throughReceiver(context);
        }
    }

    private ITelephony getTelephonyService(Context context) {
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        try {
            Class c = Class.forName(tm.getClass().getName());
            Method m = c.getDeclaredMethod("getITelephony");
            m.setAccessible(true);
            return (ITelephony) m.invoke(tm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private void throughTelephonyService(Context context) {
        ITelephony telephonyService = getTelephonyService(context);
        if (telephonyService != null) {
            telephonyService.silenceRinger();
            telephonyService.answerRingingCall();
        }
    }

    private void throughAudioManager() {
        KeyEvent downEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK);
        KeyEvent upEvent = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);
        audioManager.dispatchMediaKeyEvent(downEvent);
        audioManager.dispatchMediaKeyEvent(upEvent);
    }

    private void throughReceiver(Context context) {
        try {
            throughTelephonyService(context);
        } catch (Exception exception) {
            boolean broadcastConnected = "HTC".equalsIgnoreCase(Build.MANUFACTURER)
                    && !audioManager.isWiredHeadsetOn();

            if (broadcastConnected) {
                broadcastHeadsetConnected(false, context);
            }
            try {
                Runtime.getRuntime().exec("input keyevent " + KeyEvent.KEYCODE_HEADSETHOOK);
            } catch (IOException ioe) {
                throughPhoneHeadsetHook(context);
            } finally {
                if (broadcastConnected) {
                    broadcastHeadsetConnected(false, context);
                }
            }
        }
    }

    private void broadcastHeadsetConnected(boolean connected, Context context) {
        Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        intent.putExtra("state", connected ? 1 : 0);
        intent.putExtra("name", "mysms");
        try {
            context.sendOrderedBroadcast(intent, null);
        } catch (Exception e) {
        }
    }

    private void throughMediaController(Context context) {
        MediaSessionManager mediaSessionManager = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
        try {
            List<MediaController> controllers = mediaSessionManager.getActiveSessions(new ComponentName(context, NotificationService.class));
            for (MediaController controller : controllers) {
                if ("com.android.server.telecom".equals(controller.getPackageName())) {
                    controller.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
                    break;
                }
            }
        } catch (Exception e) {
            throughAudioManager();
        }
    }

    private void throughPhoneHeadsetHook(Context context) {
        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");

        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");
    }
}

只需按照以下方式调用acceptCall方法。
CallManager callManager = new CallManager(this);
callManager.acceptCall();

@JuanAntonioSánchezJiménez 太棒了!!很高兴知道能够解决你的问题。 - Krishna Sharma
也许我错过了一些显而易见的东西,但你从哪里获取 NotificationService?它是你编写的类,但这里没有引用,还是它是 NotificationListenerService 的实现,或者它是某个导入的类(来自哪个包)? - Artur Łysik
2
@ArturŁysik 是的,NotificationService 是一个扩展了 NotificationListenerService 的自定义服务。你可以直接使用 NotificationListenerService - Krishna Sharma

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