如何以编程方式接听/结束的Android 4.1打电话?(How to programmatical

2019-07-21 21:42发布

我写一个Android应用程序中,我需要接听来电,做一些工作,然后挂断电话。 所有的谷歌搜索后,我能找到两种不同的方式来实现这一二者均不会与最新版本的Android的工作,特别是4.1果冻豆之后。

I.)访问“com.android.internal.telephony.ITelephony”使用在广播接收器“android.intent.action.PHONE_STATE” Java反射。 下面的示例代码可在数百个相关的职位中找到:

public class PhoneCallReceiver extends BroadcastReceiver {
 Context context = null;
 private static final String TAG = "Phone call";
 private ITelephony telephonyService;

@Override
 public void onReceive(Context context, Intent intent) {
  if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) 
    return;

  Log.v(TAG, "Receving....");
  TelephonyManager telephony = (TelephonyManager) 
  context.getSystemService(Context.TELEPHONY_SERVICE);  
  try {
      Log.v(TAG, "Get getTeleService...");
      Class c = Class.forName(telephony.getClass().getName());
      Method m = c.getDeclaredMethod("getITelephony");
      m.setAccessible(true);
      telephonyService = (ITelephony) m.invoke(telephony);
      telephonyService.silenceRinger();
      Log.v(TAG, "Answering Call now...");
      telephonyService.answerRingingCall();
      Log.v(TAG, "Call answered...");
      //telephonyService.endCall();
  } catch (Exception e) {
   e.printStackTrace();
   Log.e(TAG,
           "FATAL ERROR: could not connect to telephony subsystem");
   Log.e(TAG, "Exception object: " + e);
  }
 }
}

这段代码的问题是,

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

需要这种方法工作,而此权限已被定义为“仅用于系统应用”,从机器人V 2.3。 总之,普通用户的应用程序不能再定义清单文件此权限。

II。)另一种方法是模拟耳机挂钩,这使得安卓接听电话的推动。 这是通过广播“Intent.ACTION_MEDIA_BUTTON”如下图所示的代码来完成。

public class PhoneCallReceiver extends BroadcastReceiver {
 Context context = null;
 private static final String TAG = "Phone call";

 @Override
 public void onReceive(Context context, Intent intent) {
     if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) 
         return;

     String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
     if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
         String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);

         Intent answer = new Intent(Intent.ACTION_MEDIA_BUTTON);
         answer.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
         context.sendOrderedBroadcast(answer, null);
         Log.d(TAG, "Answered incoming call from: " + number);
     }   
     return;
 } 
}

这种方法工作到安卓4.1之后,Android已经从广播“Intent.ACTION_MEDIA_BUTTON”受限用户的应用程序。

所以我的结论是,目前还没有办法,我们如何能够在搭载Android 4.1或更高版本实现这一目标。

有其他人发现的其他任何解决方案或解决此问题的?

Answer 1:

此工程于Android 2.2到4.0,现在加入尝试捕捉到它适用于4.1.2和4.2的最后一个行之后老实说不知道它是如何工作的,但它为我工作。

Log.d(tag, "InSecond Method Ans Call");
// 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));
sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");

Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
headSetUnPluggedintent.putExtra("state", 0);
headSetUnPluggedintent.putExtra("name", "Headset");
try {
    sendOrderedBroadcast(headSetUnPluggedintent, null);
} catch (Exception e) { 
    e.printStackTrace();
}

这是Android 4.1.2为我工作,以及我对4.2测试这仍给它处理的异常。

编辑为结束通话

希望这有助于都在寻找答案的和结束通话整体解决方案的人。

/**
 * Reject button click listener will reject the incoming call.
 */
private class RejectCallOnClickListener implements OnClickListener {
    @Override
    public void onClick(View v) {
        Log.d(tag, "OnRejectButton: " + "Reject OnClick");
        ignoreCall();
        exitCleanly();
    }
}

/**
 * ignore incoming calls
 */
private void ignoreCall() {
    if (USE_ITELEPHONY)
        ignoreCallAidl();
    else
        ignoreCallPackageRestart();
}
/**
 * AIDL/ITelephony technique for ignoring calls
 */
private void ignoreCallAidl() {
    try {
        // telephonyService.silenceRinger();

        telephonyService.endCall();
    } catch (RemoteException e) {
        e.printStackTrace();
        Log.d(tag, "ignoreCall: " + "Error: " + e.getMessage());

    } catch (Exception e) {
        e.printStackTrace();
        Log.d(tag, "ignoreCall" + "Error: " + e.getMessage());

    }
}
/**
 * package restart technique for ignoring calls
 */
private void ignoreCallPackageRestart() {
    ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    am.restartPackage("com.android.providers.telephony");
    am.restartPackage("com.android.phone");
}
/**
 * cleanup and exit routine
 */
private void exitCleanly() {
    unHookReceiver();
    this.finish();

}


Answer 2:

我的应用程序已经使用下面的代码来接听电话约6个月:

Intent i = new Intent(Intent.ACTION_MEDIA_BUTTON);
i.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP,
            KeyEvent.KEYCODE_HEADSETHOOK));
context.sendOrderedBroadcast(i, null);

我已经在Android版本测试了这个从2.2到4.2.2。 我还没有看到一个SecurityException广播“Intent.ACTION_MEDIA_BUTTON”在我的测试呐4.2.2设备,也没看到从表示这种异常发生的Play商店崩溃报告。

我会说,这并不总是奏效。 它不会对HTC设备由于是HTC设备具有监听有线耳机的实际堵塞HeadsetObeserver工作。 如果没有这个事件,它是目前第三方应用广播一个SecurityException,该HeadsetHook KeyEvent的那张忽略。

以前的答案是误导性的。 下面的代码块不执行任何操作:

Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
headSetUnPluggedintent.putExtra("state", 0);
headSetUnPluggedintent.putExtra("name", "Headset");
try {
    sendOrderedBroadcast(headSetUnPluggedintent, null);
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

除了产生一个SecurityException,并抓住它。

在代码工作其他的答案,这是因为KeyEvent.KEYCODE_HEADSETHOOK正在播出的。



Answer 3:

作为结论,这个线程,这里是为我的作品为Android 4.2.2的代码。

- >呼叫通过模拟耳机挂钩的推动和保持播出的try-catch由@PravinDodia在abouve线程提到的回答。 (观察到的异常被抛出,并在捕捉处理,呼叫反正回答。所以我想,我们可以忽略此异常,并继续居住生活,仿佛什么都没有发生!)

- >呼叫使用ITelephony断开。

public class PhoneCallReceiver extends BroadcastReceiver {
 Context context = null;
 private static final String TAG = "Phone call";

 @Override
 public void onReceive(Context context, Intent intent) {
     if (!intent.getAction().equals("android.intent.action.PHONE_STATE")) 
         return;
     else {
         String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);

         if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
             answerPhoneHeadsethook(context, intent);
             return;
         }
         else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
             Log.d(TAG, "CALL ANSWERED NOW!!");
             try {
                    synchronized(this) {
                        Log.d(TAG, "Waiting for 10 sec ");
                        this.wait(10000);
                    }
                }
                catch(Exception e) {
                    Log.d(TAG, "Exception while waiting !!");
                    e.printStackTrace();
                }
             disconnectPhoneItelephony(context);
             return;
         }
         else {
             Log.d(TAG, "ALL DONE ...... !!");
         }
     }  
 }

 public void answerPhoneHeadsethook(Context context, Intent intent) {
     String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
     if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
         String number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
         Log.d(TAG, "Incoming call from: " + number);
         Intent buttonUp = new Intent(Intent.ACTION_MEDIA_BUTTON);             
         buttonUp.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_HEADSETHOOK));
         try {
             context.sendOrderedBroadcast(buttonUp, "android.permission.CALL_PRIVILEGED");
             Log.d(TAG, "ACTION_MEDIA_BUTTON broadcasted...");
         }
         catch (Exception e) {
             Log.d(TAG, "Catch block of ACTION_MEDIA_BUTTON broadcast !");
         }

         Intent headSetUnPluggedintent = new Intent(Intent.ACTION_HEADSET_PLUG);
         headSetUnPluggedintent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         headSetUnPluggedintent.putExtra("state", 1); // 0 = unplugged  1 = Headset with microphone 2 = Headset without microphone
         headSetUnPluggedintent.putExtra("name", "Headset");
         // TODO: Should we require a permission?
         try {
             context.sendOrderedBroadcast(headSetUnPluggedintent, null);
             Log.d(TAG, "ACTION_HEADSET_PLUG broadcasted ...");
         }
         catch (Exception e) {
                // TODO Auto-generated catch block
                //e.printStackTrace();
                Log.d(TAG, "Catch block of ACTION_HEADSET_PLUG broadcast");
                Log.d(TAG, "Call Answered From Catch Block !!");
         }
         Log.d(TAG, "Answered incoming call from: " + number);  
    }
    Log.d(TAG, "Call Answered using headsethook");
 }

 public static void disconnectPhoneItelephony(Context context) {
     ITelephony telephonyService;
     Log.v(TAG, "Now disconnecting using ITelephony....");
      TelephonyManager telephony = (TelephonyManager) 
      context.getSystemService(Context.TELEPHONY_SERVICE);  
      try {
          Log.v(TAG, "Get getTeleService...");
          Class c = Class.forName(telephony.getClass().getName());
          Method m = c.getDeclaredMethod("getITelephony");
          m.setAccessible(true);
          telephonyService = (ITelephony) m.invoke(telephony);
          //telephonyService.silenceRinger();
          Log.v(TAG, "Disconnecting Call now...");
          //telephonyService.answerRingingCall();
          //telephonyService.endcall();
          Log.v(TAG, "Call disconnected...");
          telephonyService.endCall();
      } catch (Exception e) {
       e.printStackTrace();
       Log.e(TAG,
               "FATAL ERROR: could not connect to telephony subsystem");
       Log.e(TAG, "Exception object: " + e);
      }
 }
}

至少断开功能的工作原理,我们知道它是如何工作。 所以,谁想要开发一个呼叫限制应用程序可以继续。 对于那些像我这样谁想要接听电话,我想我们可以用这个现在只希望它不会停止在下一版本的工作。



Answer 4:

试试这个答案最终使用Pro语法呼叫。 它的工作对我罚款。

try {

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


Answer 5:

试试这个 :

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

添加权限在AndroidManifest.xml文件

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


Answer 6:

ITelephony方法不能在4.4工作,我发现耳机/媒体按钮方法仍然允许挂断前的相当长的环。

这家伙的博客文章显示,我已经作为4.4.2的Galaxy S4和HTC的一个小测试工作的新方法,即更迅速地挂断了电话,你不要么得到一个未接来电条目。

http://aprogrammersday.blogspot.co.uk/2014/05/disconnect-block-drop-calls-android-4.html

该技术使用一个运行EXEC如下,显然你可能需要使用不同数量的某些设备。

public class HangupPhoneCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (TelephonyManager.EXTRA_STATE_RINGING.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {

            Executor eS = Executors.newSingleThreadExecutor();
            eS.execute(new Runnable() {
                @Override
                public void run() {
                    Runtime runtime = Runtime.getRuntime();
                    try {
                        Log.d(TAG, "service call phone 5 \n");
                        runtime.exec("service call phone 5 \n");
                    } catch (Exception exc) {
                        Log.e(TAG, exc.getMessage());
                    }
                }
            });

            return;
        }
    }
}


Answer 7:

呼叫使用IT电话并不像三星小号二重奏某些设备断开连接。 但你仍然可以使铃声静音:)



Answer 8:

To end call in older version then 9.0
use this:


        TelephonyManager tm = (TelephonyManager)context.getSystemService(TELEPHONY_SERVICE);

        Method m1 = null;
        try {
            m1 = tm.getClass().getDeclaredMethod("getITelephony");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        m1.setAccessible(true);
        Object iTelephony = null;
        try {
            iTelephony = m1.invoke(tm);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        Method m3 = null;
        try {
            m3 = iTelephony.getClass().getDeclaredMethod("endCall");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        try {
            m3.invoke(iTelephony);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

& for pie

 TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
            if (telecomManager != null) {
                return telecomManager.endCall();
            }

Make sure your compile SDK version is 28


文章来源: How to programmatically answer/end a call in Android 4.1?