怎样才能来电可以在安卓5.0(棒棒堂)编程回答?怎样才能来电可以在安卓5.0(棒棒堂)编程回答?(H

2019-05-10 09:25发布

由于我试图创建来电定制的屏幕我想以编程方式接听来电。 我使用下面的代码,但它不是在的是Android 5.0的工作。

// Simulate a press of the headset button to pick up the call
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");

// froyo and beyond trigger on buttonUp instead of buttonDown
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");

Answer 1:

更新了Android 8.0奥利奥

这些问题即使最初要求为Android l支持,人们似乎仍然达不到这个问题的答案,所以它是值得描述的Android 8.0奥利奥有所改进。 向后兼容方法仍然如下所述。

是什么改变了?

与开始的Android 8.0奥利奥 ,该PHONE权限组还包含ANSWER_PHONE_CALLS许可 。 作为许可的名字所暗示的,拿着它可以让你的应用程序以编程方式接受通过适当的API调用来话呼叫,而无需使用反射系统周围的任何黑客行为或模拟用户。

我们如何利用这种变化?

你应该在运行时检查系统版本 ,如果您支持较旧的Android版本,以便您可以封装这个新的API调用,同时保持对那些较旧的Android版本的支持。 您应该按照请求的权限在运行时获得在运行时新的许可,因为是在较新的Android版本的标准。

在获得许可后,您的应用程序只是要简单地调用TelecomManager的acceptRingingCall方法。 基本调用看起来则如下:

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

if (tm == null) {
    // whether you want to handle this is up to you really
    throw new NullPointerException("tm == null");
}

tm.acceptRingingCall();

方法1:TelephonyManager.answerRingingCall()

因为当你有过的设备实现无限控制。

这是什么?

有TelephonyManager.answerRingingCall(),它是一个隐藏的,内部方法。 它的工作原理为已在interwebs讨论,并在一开始很有前途ITelephony.answerRingingCall()的桥梁。 它不适用于4.4.2_r1因为它被引入只有在提交83da75d为Android 4.4奇巧( 上4.4.3_r1行1537 )以及后来的“重新”在提交f1e1e77的棒棒堂( 上5.0.0_r1线3138 ),由于该如何Git的树结构。 这意味着,除非你只支持棒棒堂,这可能是基于它的微小的市场份额的,现在一个错误的决定设备,您还需要提供备用方法,如果走这路线。

我们如何使用它?

由于问题的方法是从应用程序使用SDK隐藏的,你需要使用反射来动态检查和运行时使用的方法。 如果你不熟悉反射,你可以快速阅读什么是反思,为什么是它有用吗? 。 您还可以深入挖掘细节的足迹:反射API ,如果你有兴趣这样做。

又是如何看起来代码?

// set the logging tag constant; you probably want to change this
final String LOG_TAG = "TelephonyAnswer";

TelephonyManager tm = (TelephonyManager) mContext
        .getSystemService(Context.TELEPHONY_SERVICE);

try {
    if (tm == null) {
        // this will be easier for debugging later on
        throw new NullPointerException("tm == null");
    }

    // do reflection magic
    tm.getClass().getMethod("answerRingingCall").invoke(tm);
} catch (Exception e) {
    // we catch it all as the following things could happen:
    // NoSuchMethodException, if the answerRingingCall() is missing
    // SecurityException, if the security manager is not happy
    // IllegalAccessException, if the method is not accessible
    // IllegalArgumentException, if the method expected other arguments
    // InvocationTargetException, if the method threw itself
    // NullPointerException, if something was a null value along the way
    // ExceptionInInitializerError, if initialization failed
    // something more crazy, if anything else breaks

    // TODO decide how to handle this state
    // you probably want to set some failure state/go to fallback
    Log.e(LOG_TAG, "Unable to use the Telephony Manager directly.", e);
}

这是好得是真实的!

其实,有一个小问题。 这种方法应该是全功能的,但安全经理希望呼叫者持有android.permission.MODIFY_PHONE_STATE 。 此权限在系统中只有部分文件的功能领域为第三方预计不会去碰它(你可以从文档中看到它)。 您可以尝试添加<uses-permission>它,但将没有任何好处,因为此权限的保护级别是签名|系统 ( 见核心的行1201 / AndroidManifest上5.0.0_r1 )。

你可以阅读问题34785:更新安卓的ProtectionLevel文档这是在2012年创造了回来看,我们缺少对具体的“管语法”的细节,但是从试验四周,看起来它必须作为一个功能“与”意味着所有的指定的标志必须要满足对被授予的权限。 这样的假设下工作,这将意味着你必须有你的应用程序:

  1. 安装为系统中的应用。

    这应该是罚款,可以通过要求用户使用恢复,一个ZIP安装这种生根或没有他们已经打包的自定义光盘安装谷歌应用程序时,如来完成。

  2. 签名具有相同签名的框架/碱又名系统,又名ROM。

    这就是问题的弹出。 要做到这一点,你需要有你的手放在用于签名的框架/基地的关键。 你不仅会获得访问谷歌的键的Nexus工厂的图像,但你也必须得到所有其他OEM厂商和开发商ROM键访问。 这似乎是可信并不那么你可以让你的应用程序与系统密钥签署要么做一个自定义的ROM,并要求用户切换到它(这可能是硬)或通过发现的漏洞与权限保护级别,可以绕过(这可能是很难为好)。

此外,这种行为似乎是相关发行34792:安卓果冻豆/ 4.1:android.permission.READ_LOGS不再工作这与无证开发标志一起使用相同的保护级别为好。

与TelephonyManager工作听起来不错,但除非你获得相应的许可,这是不那么容易在实践中做是行不通的。

那以其他方式使用TelephonyManager?

可悲的是,它似乎需要你保持android.permission.MODIFY_PHONE_STATE使用酷工具这反过来又意味着你将有一个很难获得访问这些方法。


方法2:服务呼叫服务代码

因为当你可以测试设备上运行的版本将与指定的代码工作。

而不能与TelephonyManager互动,也有通过该服务进行交互的可能性service的可执行文件。

这是如何运作的?

这是相当简单,但有大约比别人这条路甚至更少的文档。 我们知道肯定可执行发生在两个参数 - 服务名称和代码。

  • 我们要使用的服务名称电话

    这可以通过运行可以看到service list

  • 我们要使用的代码似乎是6,但似乎现在是5。

    看起来它是基于IBinder.FIRST_CALL_TRANSACTION + 5的许多版本,现在(从1.5_r4到4.4.4_r1 ),但本地测试期间代码5合作,接听来电。 作为Lollipo是一个巨大的更新周围的一切,这是可以理解的内部在这里改变了。

该结果与指令service call phone 5

我们如何编程利用这一点?

Java的

下面的代码是用作为概念证明一个粗略的实现。 如果你真的想继续使用这个方法,你可能想看看自由问题苏的使用指南 ,并可能切换到更充分的发展libsuperuser通过Chainfire 。

try {
    Process proc = Runtime.getRuntime().exec("su");
    DataOutputStream os = new DataOutputStream(proc.getOutputStream());

    os.writeBytes("service call phone 5\n");
    os.flush();

    os.writeBytes("exit\n");
    os.flush();

    if (proc.waitFor() == 255) {
        // TODO handle being declined root access
        // 255 is the standard code for being declined root for SU
    }
} catch (IOException e) {
    // TODO handle I/O going wrong
    // this probably means that the device isn't rooted
} catch (InterruptedException e) {
    // don't swallow interruptions
    Thread.currentThread().interrupt();
}

表现

<!-- Inform the user we want them root accesses. -->
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>

这是否真的需要root权限?

可悲的是,它似乎很。 您可以尝试使用的Runtime.exec就可以了,但我没能得到任何运气这条路线。

这怎么稳定是?

我很高兴你问。 由于没有被记录,这可以在不同版本的断裂,由看似代码差如图所示的上方。 该服务的名称可能应保持手机在各种版本,但我们都知道,代码值可以改变跨多个构建相同版本的依次(,比方说,OEM的皮肤内部修改),打破使用的方法。 因此,值得一提的测试发生在Nexus 4(鲭/奥卡姆)。 我个人建议你不要使用这种方法,但我无法找到一个更稳定的方法,我相信这是最好的射手。


原始的方法:耳机键码的意图

对于时候,你必须解决。

下面的部分是强烈影响此答案由莱利Ç 。

张贴在原来的问题模拟耳机意向的方法似乎只播出正如人们所期望的,但它似乎没有完成接听电话的目标。 虽然似乎是应该处理这些意图发生的代码,他们根本不被关心,这有意味着必须有某种新的对策反对这种方法的地方。 该日志不显示任何感兴趣的东西,我不个人认为通过Android源挖掘,这将是值得只是由于谷歌的介绍,很容易打破反正使用的方法略有变化的可能性。

有什么我们现在可以做什么?

该行为可以使用输入的可执行始终如一转载。 它发生在一个键码的说法,对此我们简单地传递KeyEvent.KEYCODE_HEADSETHOOK 。 该方法甚至不需要root访问权限使其适合于常见的使用情况在一般公众,但在方法的小缺点 - 耳机按钮按下事件不能被指定为需要的权限,这意味着它像一个真正的按下按钮和气泡向上穿过整条产业链,而这又意味着你必须要谨慎,什么时候按下按钮模拟,因为它可以,例如,触发音乐播放器开始播放,如果没有其他人更高的优先级已准备好处理事件。

码?

new Thread(new Runnable() {

    @Override
    public void run() {
        try {
            Runtime.getRuntime().exec("input keyevent " +
                    Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
        } catch (IOException e) {
            // Runtime.exec(String) had an I/O problem, try to fall back
            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));

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

}).start();

TL;博士

这里是Android 8.0奥利奥,后来一个很好的公共API。

有前到Android 8.0奥利奥没有公开的API。 内部API是禁止入内或简单地不文档。 您应该谨慎行事。



Answer 2:

全工作的解决方案是基于@Valter Strods代码。

得到它的工作,你要执行的代码是其中锁定屏幕上显示(不可见)的活动。

AndroidManifest.xml中

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

<activity android:name="com.mysms.android.lib.activity.AcceptCallActivity"
        android:launchMode="singleTop"
        android:excludeFromRecents="true"
        android:taskAffinity=""
        android:configChanges="orientation|keyboardHidden|screenSize"
        android:theme="@style/Mysms.Invisible">
    </activity>

呼叫接受活动

package com.mysms.android.lib.activity;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.WindowManager;

import org.apache.log4j.Logger;

import java.io.IOException;

public class AcceptCallActivity extends Activity {

     private static Logger logger = Logger.getLogger(AcceptCallActivity.class);

     private static final String MANUFACTURER_HTC = "HTC";

     private KeyguardManager keyguardManager;
     private AudioManager audioManager;
     private CallStateReceiver callStateReceiver;

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
         audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
     }

     @Override
     protected void onResume() {
         super.onResume();

         registerCallStateReceiver();
         updateWindowFlags();
         acceptCall();
     }

     @Override
     protected void onPause() {
         super.onPause();

         if (callStateReceiver != null) {
              unregisterReceiver(callStateReceiver);
              callStateReceiver = null;
         }
     }

     private void registerCallStateReceiver() {
         callStateReceiver = new CallStateReceiver();
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
         registerReceiver(callStateReceiver, intentFilter);
     }

     private void updateWindowFlags() {
         if (keyguardManager.inKeyguardRestrictedInputMode()) {
              getWindow().addFlags(
                       WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         } else {
              getWindow().clearFlags(
                       WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
                                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
                                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         }
     }

     private void acceptCall() {

         // for HTC devices we need to broadcast a connected headset
         boolean broadcastConnected = MANUFACTURER_HTC.equalsIgnoreCase(Build.MANUFACTURER)
                  && !audioManager.isWiredHeadsetOn();

         if (broadcastConnected) {
              broadcastHeadsetConnected(false);
         }

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

              } catch (IOException e) {
                  // 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);
              }
         } finally {
              if (broadcastConnected) {
                  broadcastHeadsetConnected(false);
              }
         }
     }

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

     private class CallStateReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
              finish();
         }
     }
}

样式

<style name="Mysms.Invisible">
    <item name="android:windowFrame">@null</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowAnimationStyle">@null</item>
</style>

最后调用神奇!

Intent intent = new Intent(context, AcceptCallActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(intent);


Answer 3:

以下是为我工作的一种替代方法。 它发出直接使用的MediaController API电信服务器的关键事件。 这就要求应用程序有BIND_NOTIFICATION_LISTENER_SERVICE许可被赋予的从用户访问的通知明确授予:

@TargetApi(Build.VERSION_CODES.LOLLIPOP) 
void sendHeadsetHookLollipop() {
    MediaSessionManager mediaSessionManager =  (MediaSessionManager) getApplicationContext().getSystemService(Context.MEDIA_SESSION_SERVICE);

    try {
        List<MediaController> mediaControllerList = mediaSessionManager.getActiveSessions 
                     (new ComponentName(getApplicationContext(), NotificationReceiverService.class));

        for (MediaController m : mediaControllerList) {
             if ("com.android.server.telecom".equals(m.getPackageName())) {
                 m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
                 log.info("HEADSETHOOK sent to telecom server");
                 break;
             }
        }
    } catch (SecurityException e) {
        log.error("Permission error. Access to notification not granted to the app.");      
    }  
}

NotificationReceiverService.class在上面的代码可能只是一个空的类。

import android.service.notification.NotificationListenerService;

public class NotificationReceiverService extends NotificationListenerService{
     public NotificationReceiverService() {
     }
}

与在清单中相应的部分:

    <service android:name=".NotificationReceiverService" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
        android:enabled="true" android:exported="true">
    <intent-filter>
         <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>

由于该事件的目标是明确的可能应该避免引发媒体播放器的任何副作用。

注:振铃事件之后,电信服务器可能不会立即激活。 对于这个可靠地工作,它可能是有用的应用程序来实现MediaSessionManager.OnActiveSessionsChangedListener来监控电信服务器被激活,发送事件之前。

更新:

Android的O,一个需要模拟ACTION_DOWNACTION_UP ,否则上面没有任何影响。 即需要以下:

m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK));
m.dispatchMediaButtonEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));

但由于官方电话接听电话是可由于Android O(见上面的答案),有可能不再需要这个技巧,除非被套牢的Android O.前旧的编译API级别



Answer 4:

为了详细说明通过@Muzikant答案一点点,并稍作修改的工作我的设备上有点清洁,尝试input keyevent 79 ,该常数KeyEvent.KEYCODE_HEADSETHOOK 。 不客气:

    new Thread(new Runnable() {

        @Override
        public void run() {

            try {

                Runtime.getRuntime().exec( "input keyevent " + KeyEvent.KEYCODE_HEADSETHOOK );
            }
            catch (Throwable t) {

                // do something proper here.
            }
        }
    }).start();

原谅相当不错编码约定,我不是太的Runtime.exec深谙()调用。 请注意,我的设备是不是扎根,我也没有要求root权限。

这种方法的问题在于,它只有在特定条件下工作(对我来说)。 也就是说,如果我跑从用户通话时响铃,呼叫答案就好了选择一个菜单选项上线。 如果我从监控来电状态的接收器中运行它,它就会被完全忽略。

所以,在我的Nexus 5它非常适用于用户驱动的应答,并应满足定制呼叫屏幕的目的。 它只是不会为任何类型的自动呼叫控制型应用程序。

另外值得注意的是所有可能的注意事项,包括这也可能会停止更新或两个工作。



Answer 5:

通过ADB命令如何拿起亚行通话

请记住,Android是用Linux的在前端一个巨大的JVM。 你可以下载一个命令行应用程序和根的电话,现在你必须做所有正常的事情常规的Linux计算机和命令行。 运行脚本,你甚至可以SSH到它(OpenVPN的伎俩)



Answer 6:

由于@notz是为我工作的Lolillop答案。 为了保持该代码与旧的Android SDK的工作,你可以做这样的代码:

if (Build.VERSION.SDK_INT >= 21) {  
    Intent answerCalintent = new Intent(context, AcceptCallActivity.class);  
    answerCalintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | 
                             Intent.FLAG_ACTIVITY_CLEAR_TASK  | 
                             Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    context.startActivity(answerCalintent);  
}  
else {  
  if (telephonyService != null) {  
    try {  
        telephonyService.answerRingingCall();  
    }  
    catch (Exception e) {  
        answerPhoneHeadsethook();  
    }  
  }  
}  


Answer 7:

后如何自动应答呼叫打开免提电话。

我解决了以上setSpeakerphoneOn我的问题。 我认为它值得张贴在这里,因为使用情况自动接听来电,常常还需要扬声器是有用的。 再次感谢大家对这个线程,多么真棒工作。

这对我的作品在Android 5.1.1上我的Nexus 4没有根。 ;)

权限要求:

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

Java代码:

// this means the phone has answered
if(state==TelephonyManager.CALL_STATE_OFFHOOK)
{
    // try and turn on speaker phone
    final Handler mHandler = new Handler();
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            AudioManager audioManager = (AudioManager) localContext.getSystemService(Context.AUDIO_SERVICE);

            // this doesnt work without android.permission.MODIFY_PHONE_STATE
            // audioManager.setMode(AudioManager.MODE_IN_CALL);

            // weirdly this works
            audioManager.setMode(AudioManager.MODE_NORMAL); // this is important
            audioManager.setSpeakerphoneOn(true);

            // note the phone interface won't show speaker phone is enabled
            // but the phone speaker will be on
            // remember to turn it back off when your done ;)
        }
    }, 500); // half a second delay is important or it might fail
}


Answer 8:

运行下面的命令作为根:

input keyevent 5

在模拟的KeyEvents更多细节在这里 。

你可以用我创造了这个基类 ,从您的应用程序以root身份运行命令。



Answer 9:

测试:首先添加的权限,然后使用killCall()挂断使用answerCall()接听电话

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


public void killCall() {
    try {
        TelephonyManager telephonyManager =
                (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);

        Class classTelephony = Class.forName(telephonyManager.getClass().getName());
        Method methodGetITelephony = classTelephony.getDeclaredMethod("getITelephony");

        methodGetITelephony.setAccessible(true);

        Object telephonyInterface = methodGetITelephony.invoke(telephonyManager);

        Class telephonyInterfaceClass =
                Class.forName(telephonyInterface.getClass().getName());
        Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("endCall");

        methodEndCall.invoke(telephonyInterface);

    } catch (Exception ex) {
        Log.d(TAG, "PhoneStateReceiver **" + ex.toString());
    }
}

public void answerCall() {
    try {
        Runtime.getRuntime().exec("input keyevent " +
                Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));

    } catch (IOException e) {
        answerRingingCallWithIntent();
    }
}

public void answerRingingCallWithIntent() {
    try {
        Intent localIntent1 = new Intent(Intent.ACTION_HEADSET_PLUG);
        localIntent1.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        localIntent1.putExtra("state", 1);
        localIntent1.putExtra("microphone", 1);
        localIntent1.putExtra("name", "Headset");
        getContext().sendOrderedBroadcast(localIntent1, "android.permission.CALL_PRIVILEGED");

        Intent localIntent2 = new Intent(Intent.ACTION_MEDIA_BUTTON);
        KeyEvent localKeyEvent1 = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_HEADSETHOOK);
        localIntent2.putExtra(Intent.EXTRA_KEY_EVENT, localKeyEvent1);
        getContext().sendOrderedBroadcast(localIntent2, "android.permission.CALL_PRIVILEGED");

        Intent localIntent3 = new Intent(Intent.ACTION_MEDIA_BUTTON);
        KeyEvent localKeyEvent2 = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK);
        localIntent3.putExtra(Intent.EXTRA_KEY_EVENT, localKeyEvent2);
        getContext().sendOrderedBroadcast(localIntent3, "android.permission.CALL_PRIVILEGED");

        Intent localIntent4 = new Intent(Intent.ACTION_HEADSET_PLUG);
        localIntent4.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
        localIntent4.putExtra("state", 0);
        localIntent4.putExtra("microphone", 1);
        localIntent4.putExtra("name", "Headset");
        getContext().sendOrderedBroadcast(localIntent4, "android.permission.CALL_PRIVILEGED");
    } catch (Exception e2) {
        e2.printStackTrace();
    }
}


Answer 10:

仅供参考,如果你有兴趣在如何结束在Android O,瓦尔特的正在进行的通话Method 1: TelephonyManager.answerRingingCall()如果你改变你的调用是方法工作endCall

它只需要android.permission.CALL_PHONE许可。

下面的代码:

// set the logging tag constant; you probably want to change this
final String LOG_TAG = "TelephonyAnswer";

public void endCall() {
    TelephonyManager tm = (TelephonyManager) mContext
            .getSystemService(Context.TELEPHONY_SERVICE);

    try {
        if (tm == null) {
            // this will be easier for debugging later on
            throw new NullPointerException("tm == null");
        }

        // do reflection magic
        tm.getClass().getMethod("endCall").invoke(tm);
    } catch (Exception e) {
        // we catch it all as the following things could happen:
        // NoSuchMethodException, if the answerRingingCall() is missing
        // SecurityException, if the security manager is not happy
        // IllegalAccessException, if the method is not accessible
        // IllegalArgumentException, if the method expected other arguments
        // InvocationTargetException, if the method threw itself
        // NullPointerException, if something was a null value along the way
        // ExceptionInInitializerError, if initialization failed
        // something more crazy, if anything else breaks

        // TODO decide how to handle this state
        // you probably want to set some failure state/go to fallback
        Log.e(LOG_TAG, "Unable to use the Telephony Manager directly.", e);
    }
}


文章来源: How can incoming calls be answered programmatically in Android 5.0 (Lollipop)?