【问题标题】:Android call answering programmaticallyAndroid 以编程方式接听电话
【发布时间】:2016-04-12 07:01:23
【问题描述】:

是否可以在android中以编程方式接听电话?

我发现了一些不可能的地方,但随后安装了应用程序https://play.google.com/store/apps/details?id=com.a0softus.autoanswer 它工作正常。

我搜索了很多,尝试了很多东西,而且电话拒绝工作正常但电话接听不起作用。

我已尝试使用以下代码来接听电话,如下所示:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.KeyEvent;

import java.io.IOException;
import java.lang.reflect.Method;

import app.com.bikemode.MainActivity;
import app.com.bikemode.R;

public class IncomingCallReceiver extends BroadcastReceiver {
    String incomingNumber = "";
    AudioManager audioManager;
    TelephonyManager telephonyManager;
    Context context;
    private MediaPlayer mediaPlayer;

    public void onReceive(Context context, Intent intent) {
        // Get AudioManager
        this.context = context;
        mediaPlayer = new MediaPlayer();
        audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        // Get TelephonyManager
        telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                // Get incoming number
                incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);

            }
        }

        if (!incomingNumber.equals("")) {
            // Get an instance of ContentResolver
           /* ContentResolver cr=context.getContentResolver();
            // Fetch the matching number
            Cursor numbers=cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,  new  String[]{ContactsContract.CommonDataKinds.Phone.CONTACT_ID,ContactsContract.CommonDataKinds.Phone.NUMBER},  ContactsContract.CommonDataKinds.Phone.NUMBER +"=?", new String[]{incomingNumber},  null);
            if(numbers.getCount()<=0){ // The incoming number is not  found in the contacts list*/
            // Turn on the mute
            //audioManager.setStreamMute(AudioManager.STREAM_RING,  true);
            // Reject the call
            //rejectCall();
            // Send the rejected message ton app
            //startApp(context,incomingNumber);
            // }

            //audioManager.setStreamMute(AudioManager.STREAM_RING, true);
            //rejectCall();
            //startApp(context, incomingNumber);
            acceptCall();
        }
    }


    private void startApp(Context context, String number) {
        Intent intent = new Intent(context, MainActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.putExtra("number", "Rejected incoming number:" + number);
        context.startActivity(intent);
    }

    private void rejectCall() {
        try {

            // Get the getITelephony() method
            Class<?> classTelephony = Class.forName(telephonyManager.getClass().getName());
            Method method = classTelephony.getDeclaredMethod("getITelephony");
            // Disable access check
            method.setAccessible(true);
            // Invoke getITelephony() to get the ITelephony interface
            Object telephonyInterface = method.invoke(telephonyManager);
            // Get the endCall method from ITelephony
            Class<?> telephonyInterfaceClass = Class.forName(telephonyInterface.getClass().getName());
            Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("endCall");
            // Invoke endCall()
            methodEndCall.invoke(telephonyInterface);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    private void acceptCall() {
        try {
           /* // Get the getITelephony() method
            Class<?> classTelephony = Class.forName(telephonyManager.getClass().getName());
            Method method = classTelephony.getDeclaredMethod("getITelephony");
            // Disable access check
            method.setAccessible(true);
            // Invoke getITelephony() to get the ITelephony interface
            Object telephonyInterface = method.invoke(telephonyManager);
            // Get the endCall method from ITelephony
            Class<?> telephonyInterfaceClass = Class.forName(telephonyInterface.getClass().getName());
            Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("answerRingingCall");
            // Invoke endCall()
            methodEndCall.invoke(telephonyInterface);*/
            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");
            playAudio(R.raw.a);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }


    private void playAudio(int resid) {
        AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
        try {
            mediaPlayer.reset();
            mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
            mediaPlayer.prepare();
            mediaPlayer.start();
            afd.close();
        } catch (IllegalArgumentException e) {
            Log.w("Rahul Log",e.getMessage());
        } catch (IllegalStateException e) {
            Log.w("Rahul Log", e.getMessage());
        } catch (IOException e) {
            Log.w("Rahul Log", e.getMessage());
        }
    }
}

功能拒绝呼叫工作正常,但接受呼叫不工作。

【问题讨论】:

标签: java android phone-call telephonymanager


【解决方案1】:

我的应用也遇到了同样的问题。为接受来电设置一些延迟(~3000 毫秒)。您还需要在不同的线程中调用acceptCall() 方法。

参考How can incoming calls be answered programmatically in Android 5.0 (Lollipop)?

new Thread(new Runnable() {
            @Override
            public void run() {
                acceptCall();
            }
        }).start();

private void acceptCall() {
        try {
            // Get the getITelephony() method
            Class<?> classTelephony = Class.forName(telephonyManager.getClass().getName());
            Method method = classTelephony.getDeclaredMethod("getITelephony");
            // Disable access check
            method.setAccessible(true);
            // Invoke getITelephony() to get the ITelephony interface
            Object telephonyInterface = method.invoke(telephonyManager);
            // Get the endCall method from ITelephony
            Class<?> telephonyInterfaceClass = Class.forName(telephonyInterface.getClass().getName());
            Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("answerRingingCall");
            // Invoke endCall()
            methodEndCall.invoke(telephonyInterface);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

【讨论】:

  • 嗨 Daaud.. 感谢您的回复.. 我已经使用了您的代码并测试了它给我的原因:java.lang.SecurityException:用户 10228 和当前进程都没有 android.permission.MODIFY_PHONE_STATE .你能帮我解决这个...
  • 抱歉,MODIFY_PHONE_STATE 是系统专属权限,因此您无法在您的应用中访问或使用此权限。
  • 有没有其他方法可以做到这一点,因为 Play 商店中的某些应用程序也在做同样的工作?
  • 嗨,Daud Arfin。非常感谢它真的有效。我已经在 Marshmallow 上测试过......
【解决方案2】:

这对我有用。

private void answerCall() {
    Log.d(TAG, "Answering call");
    TelephonyManager telephony = (TelephonyManager)
            context.getSystemService(Context.TELEPHONY_SERVICE);
    try {
        Class c = Class.forName(telephony.getClass().getName());
        Method m = c.getDeclaredMethod("getITelephony");
        m.setAccessible(true);
        telephonyService = (ITelephony) m.invoke(telephony);
        //telephonyService.silenceRinger();
        telephonyService.answerRingingCall();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

【讨论】:

  • 谢谢。但是在复制代码后出现错误“无法解析符号 ITelephony”
  • 确保包名保持不变。 package com.android.internal.telephony; public interface ITelephony { boolean endCall(); void answerRingingCall(); void silenceRinger(); }
  • 嗨,谢谢,创建相同的包名称后编译错误消失了,但在调用时,java.lang.SecurityException:用户 10228 和当前进程都没有 android.permission.MODIFY_PHONE_STATE 异常出现在函数 telephonyService.answerRingingCall( );.你能帮我解决这个问题吗?
  • 同样的问题
  • @RahulVats - 请添加以下权限 &lt;uses-permission android:name="android.permission.CALL_PHONE" /&gt; &lt;uses-permission android:name="android.permission.READ_PHONE_STATE" /&gt; 另外,您可能需要为 android.permission.MODIFY_PHONE_STATE 添加 Marshmallow 的运行时权限
【解决方案3】:
public void answerCall(){  

   try {
                        // logger.debug("execute input keycode headset hook");
                        Runtime.getRuntime().exec("input keyevent " +
                                Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));


                    } catch (IOException e) {

                        Log.e("Call Exception ",e.toString());
                        HelperMethods.showToastS(getBaseContext(),"Call Exception one "+e.toString());
                        // Runtime.exec(String) had an I/O problem, try to fall back
                        //    logger.debug("send keycode headset hook intents");
                        String enforcedPerm = "android.permission.CALL_PRIVILEGED";
                        Intent btnDown = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
                                Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_DOWN,
                                        KeyEvent.KEYCODE_HEADSETHOOK));
                        Intent btnUp = new Intent(Intent.ACTION_MEDIA_BUTTON).putExtra(
                                Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
                                        KeyEvent.KEYCODE_HEADSETHOOK));

                         sendOrderedBroadcast(btnDown, enforcedPerm);
                        sendOrderedBroadcast(btnUp, enforcedPerm);
                    }
}

【讨论】:

    【解决方案4】:

    这适用于我在 android 版本 9 中

    点击回答中的此代码...

    if (VERSION.SDK_INT >= 26) {
                    IncomingActivity incomingActivity = IncomingActivity.this;
                    new Thread(new C1736O(incomingActivity)).start();
                } else if (VERSION.SDK_INT >= 21) {
                    IncomingActivity incomingActivity2 = IncomingActivity.this;
                    new Thread(new C1735LN(incomingActivity2)).start();
                } else {
                    Intent intent = new Intent("android.intent.action.MEDIA_BUTTON");
                    intent.putExtra("android.intent.extra.KEY_EVENT", new KeyEvent(0, 79));
                    IncomingActivity.this.sendOrderedBroadcast(intent, "android.permission.CALL_PRIVILEGED");
                    Intent intent2 = new Intent("android.intent.action.MEDIA_BUTTON");
                    intent2.putExtra("android.intent.extra.KEY_EVENT", new KeyEvent(1, 79));
                    IncomingActivity.this.sendOrderedBroadcast(intent2, "android.permission.CALL_PRIVILEGED");
                }
    

    【讨论】:

    • 您是否也使用过像 truecaller 这样的默认拨号器应用程序??
    • 可以分享一些资源来学习吗??
    猜你喜欢
    • 1970-01-01
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多