Razvan Gabriel Razvan Gabriel - 3 years ago 182
Android Question

Dial multiple numbers one by one programmatically | Android

I am trying to develop a feature for an app where you have a list of "codes" that you enter and that are dialed one by one. I have looked over TelephonyManager and followed a tutorial on developing a broadcast receiver with a listener for responses but it does not always work as it should.
One idea was to store all the numbers necessary in SharedPref. If the Activity (only created for the intent towards dialer) went into onStop() (meaning that above, the dialer screen was on) and then into onResume() (call ended and activity resumed), I would remove the number last dialed from the SharedPref and then, if any remained, open the dialer again. The broadcast made sure than once the state flow of the TelephonyManager was "OFFHOOK => IDLE", it would return the user to the Activity . Short story, it did not always perform as it should have.

How should I tackle the problem ?

EDIT

My curent solution was to


  1. Create a doPhoneCall() function that would handle the intent creation and deployment itself.

    @Override
    protected void doPhoneCall(){
    super.onResume();
    wentIntoCall = false;
    /** More code here for dialing */
    }

  2. Place this function into the onResume(). Even if the onResume will be called multiple times, the wentIntoCall boolean will make sure that the function won't be called multiple times.

    @Override
    protected void onResume() {
    super.onResume();
    if(wentIntoCall)
    doPhoneCall();
    }

  3. Having in mind that after a call, the phone should return to its previous state, so it would return to the Activity in which we are doing are call, we will add to the activity a CallListener, and in the case of IDLE, based on the tutorial linked above, we make the wentIntoCall be true. ( The activity will go into onResume() and, upon seeing that the boolean is true, it will initialize the next call ).

    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
    }



My final question : is this the right way to handle this functionality, or should I try to come up with another implementation of it ?

EDIT 2

Looks like my "codes", being USSD codes, are not behaving like normal phone calls.. So for normal phone calls the code above seems to work, but for dialing codes, not that much. I have "downgraded" my solution to a simple for-loop. Seems to be working fine now.

Answer Source

I dont kn ow for android O , but for android 6.0 > You cant detect answer in direct way . Call no exist number and see PhoneStateListener what will trigger .

Make public static array , add all your numbers intro array . I made services . Insert permissions in manifest make your own action also ( NEXT_CALL for example ) .

Than easy make intent for 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();

You must use timeout interval about 10 sec for next call.

Heres little help func - end call and phoneState handler :

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

Thanks for : "meaning that above, the dialer screen was on" nice catch.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download