以编程方式一个接一个地拨打多个号码 | Android
Dial multiple numbers one by one programmatically | Android
我正在尝试为一个应用程序开发一项功能,您可以在其中输入 "codes" 的列表,然后一个一个地拨打。我查看了 TelephonyManager 并遵循 tutorial 开发带有响应侦听器的广播接收器,但它并不总是按预期工作。
一个想法是将所有必要的数字存储在 SharedPref 中。如果 Activity(仅为拨号器的意图而创建)进入 onStop()(意味着在上面,拨号器屏幕打开)然后进入 onResume()(调用结束并 activity 恢复),我会从 SharedPref 中删除上次拨打的号码,然后,如果还有的话,再次打开拨号器。广播确保一旦 TelephonyManager 的状态流为 "OFFHOOK => IDLE",它将 return 用户转到 Activity 。简而言之,它并不总是发挥应有的作用。
我该如何解决这个问题?
编辑
我目前的解决方案是
创建一个 doPhoneCall() 函数来处理意图创建和部署本身。
@Override
protected void doPhoneCall(){
super.onResume();
wentIntoCall = false;
/** More code here for dialing */
}
将此函数放入 onResume()。即使 onResume 会被多次调用,wentIntoCall 布尔值也会确保该函数不会被多次调用。
@Override
protected void onResume() {
super.onResume();
if(wentIntoCall)
doPhoneCall();
}
请记住,在调用之后,phone 应该 return 到它之前的状态,所以它会 return 到 Activity我们正在做的是调用,我们将向 activity 添加一个 CallListener,在 IDLE 的情况下,根据上面链接的教程,我们使 wentIntoCall 为真。 ( activity 将进入 onResume() 并且,在看到布尔值为真时,它将初始化下一个调用)。
case TelephonyManager.CALL_STATE_IDLE:
Log.e(TAG, "CALL_STATE_IDLE==>"+incoming_number);
if((prev_state == TelephonyManager.CALL_STATE_OFFHOOK)){
prev_state=state;
wentIntoCall = true;
//Answered Call which is ended
}
if((prev_state == TelephonyManager.CALL_STATE_RINGING)){
prev_state=state;
wentIntoCall = true;
//Rejected or Missed call
}
我的最后一个问题:这是处理此功能的正确方法吗,还是我应该尝试想出另一种实现方法?
编辑 2
看起来我的 "codes",是 USSD 代码,不像正常的 phone 呼叫那样工作。所以对于正常的 phone 呼叫,上面的代码似乎有效,但用于拨号代码,没那么多。我有 "downgraded" 我的简单 for 循环解决方案。现在似乎工作正常。
作为旁注,在 Android O 开发者预览版中有一个新的 API,它允许您 send a USSD request 并注册一个回调以接收其结果。对于 Android 的较新版本,这可能会更好地满足您的需求。
我不知道 android O,但 android 6.0 > 您无法直接检测答案。呼叫不存在的号码并查看 PhoneStateListener 在一种情况下会触发什么并跟踪成功的呼叫。
创建 public 静态数组,添加所有数字 intro 数组。
我发了服务。在清单中插入权限也可以让您自己执行操作(例如 NEXT_CALL)。
比 startServices 更容易制作意图:
SharedPreferences settings;
SharedPreferences.Editor SAVES;
Intent serviceIntent = new Intent(MainActivity.this, ServiceForCalls.class);
serviceIntent.setAction("xxx.xxx.NEXT_CALL");
startService(serviceIntent);
isCalling = true;
SAVES.putBoolean( "isCalling" , isCalling );
SAVES.commit();
SAVES.apply();
下次调用必须使用超时间隔约 10 秒。
这里有一点帮助 func - 结束呼叫和 phoneState 处理程序 :
void END_CALL () throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Class c = null;
try {
c = Class.forName(tm.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method m = null;
try {
m = c.getDeclaredMethod("getITelephony");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
if ( SIGNAL_STOP == false ) {
timerHandlerServicesStartNewNumber.postDelayed(timerRunnableServicesStartNewNumber, 1000);
}
}
private class PhoneStateChangeListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.println( Log.INFO , "RINGING" , "SERVICES%%%%%%%%%%%%%%%%RINGING%%%%%%%%%%%%%%%%%%");
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%");
if (!wasRinging) {
// Start your new activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%");
if (SIGNAL_STOP == false) {
timerHandlerServices.postDelayed(timerRunnableServices, 10000);
}
} else {
// Cancel your old activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
}
// this should be the last piece of code before the break
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.println( Log.INFO , "IDLE BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%IDLE%%%%%%%%%%%%%%%%%%%");
// this should be the last piece of code before the break
wasRinging = false;
break;
}
}
}
感谢:"meaning that above, the dialer screen was on" 不错。
我正在尝试为一个应用程序开发一项功能,您可以在其中输入 "codes" 的列表,然后一个一个地拨打。我查看了 TelephonyManager 并遵循 tutorial 开发带有响应侦听器的广播接收器,但它并不总是按预期工作。 一个想法是将所有必要的数字存储在 SharedPref 中。如果 Activity(仅为拨号器的意图而创建)进入 onStop()(意味着在上面,拨号器屏幕打开)然后进入 onResume()(调用结束并 activity 恢复),我会从 SharedPref 中删除上次拨打的号码,然后,如果还有的话,再次打开拨号器。广播确保一旦 TelephonyManager 的状态流为 "OFFHOOK => IDLE",它将 return 用户转到 Activity 。简而言之,它并不总是发挥应有的作用。
我该如何解决这个问题?
编辑
我目前的解决方案是
创建一个 doPhoneCall() 函数来处理意图创建和部署本身。
@Override protected void doPhoneCall(){ super.onResume(); wentIntoCall = false; /** More code here for dialing */ }
将此函数放入 onResume()。即使 onResume 会被多次调用,wentIntoCall 布尔值也会确保该函数不会被多次调用。
@Override protected void onResume() { super.onResume(); if(wentIntoCall) doPhoneCall(); }
请记住,在调用之后,phone 应该 return 到它之前的状态,所以它会 return 到 Activity我们正在做的是调用,我们将向 activity 添加一个 CallListener,在 IDLE 的情况下,根据上面链接的教程,我们使 wentIntoCall 为真。 ( activity 将进入 onResume() 并且,在看到布尔值为真时,它将初始化下一个调用)。
case TelephonyManager.CALL_STATE_IDLE: Log.e(TAG, "CALL_STATE_IDLE==>"+incoming_number); if((prev_state == TelephonyManager.CALL_STATE_OFFHOOK)){ prev_state=state; wentIntoCall = true; //Answered Call which is ended } if((prev_state == TelephonyManager.CALL_STATE_RINGING)){ prev_state=state; wentIntoCall = true; //Rejected or Missed call }
我的最后一个问题:这是处理此功能的正确方法吗,还是我应该尝试想出另一种实现方法?
编辑 2
看起来我的 "codes",是 USSD 代码,不像正常的 phone 呼叫那样工作。所以对于正常的 phone 呼叫,上面的代码似乎有效,但用于拨号代码,没那么多。我有 "downgraded" 我的简单 for 循环解决方案。现在似乎工作正常。
作为旁注,在 Android O 开发者预览版中有一个新的 API,它允许您 send a USSD request 并注册一个回调以接收其结果。对于 Android 的较新版本,这可能会更好地满足您的需求。
我不知道 android O,但 android 6.0 > 您无法直接检测答案。呼叫不存在的号码并查看 PhoneStateListener 在一种情况下会触发什么并跟踪成功的呼叫。
创建 public 静态数组,添加所有数字 intro 数组。 我发了服务。在清单中插入权限也可以让您自己执行操作(例如 NEXT_CALL)。
比 startServices 更容易制作意图:
SharedPreferences settings;
SharedPreferences.Editor SAVES;
Intent serviceIntent = new Intent(MainActivity.this, ServiceForCalls.class);
serviceIntent.setAction("xxx.xxx.NEXT_CALL");
startService(serviceIntent);
isCalling = true;
SAVES.putBoolean( "isCalling" , isCalling );
SAVES.commit();
SAVES.apply();
下次调用必须使用超时间隔约 10 秒。
这里有一点帮助 func - 结束呼叫和 phoneState 处理程序 :
void END_CALL () throws InvocationTargetException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException {
tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Class c = null;
try {
c = Class.forName(tm.getClass().getName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method m = null;
try {
m = c.getDeclaredMethod("getITelephony");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
m.setAccessible(true);
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object
c = Class.forName(telephonyService.getClass().getName()); // Get its class
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method
m.setAccessible(true); // Make it accessible
m.invoke(telephonyService); // invoke endCall()
if ( SIGNAL_STOP == false ) {
timerHandlerServicesStartNewNumber.postDelayed(timerRunnableServicesStartNewNumber, 1000);
}
}
private class PhoneStateChangeListener extends PhoneStateListener {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.println( Log.INFO , "RINGING" , "SERVICES%%%%%%%%%%%%%%%%RINGING%%%%%%%%%%%%%%%%%%");
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%");
if (!wasRinging) {
// Start your new activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%");
if (SIGNAL_STOP == false) {
timerHandlerServices.postDelayed(timerRunnableServices, 10000);
}
} else {
// Cancel your old activity
Log.println( Log.INFO , "OFFHOOK BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
}
// this should be the last piece of code before the break
wasRinging = true;
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.println( Log.INFO , "IDLE BROADCAST" , "SERVICES%%%%%%%%%%%%%%%%%IDLE%%%%%%%%%%%%%%%%%%%");
// this should be the last piece of code before the break
wasRinging = false;
break;
}
}
}
感谢:"meaning that above, the dialer screen was on" 不错。