3

I need to end the call after the ring has been made (kind of like a missed call). I used BroadcastReceiver and PhoneStateListener to monitor the states.

The problem is I'm receiving a broadcast and also the phonenumber, and the listener works well - it goes inside the switch and executes the case intended, but it doesn't execute the endCall method of the ITelephony interface. Here's my code:

Manifest:

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
    tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.WRITE_CALL_LOG" />
<receiver
    android:name=".EndCall"
    android:enabled="true" >
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>

EndCall.java

public class EndCall extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("Debug", "Received a broadcast...");
        String phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        Log.i("Debug", "Phone number: " + phonenumber);
        TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        EndCallListener callListener = new EndCallListener(context, tm);
        tm.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE);
    }
}

EndCallListener.java:

public class EndCallListener extends PhoneStateListener {
    Context context;
    TelephonyManager tm;
    public EndCallListener(Context context, TelephonyManager tm) {
        this.context = context;
        this.tm = tm;
    }
    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        switch (state) {
            case TelephonyManager.CALL_STATE_OFFHOOK:
                Log.i("Debug", "OFFHOOK");
                try {
                    Log.i("Debug", "Inside try...");
                    Class c = Class.forName(tm.getClass().getName());
                    Method m = c.getDeclaredMethod("getITelephony");
                    ITelephony telephonyService = (ITelephony) m.invoke(tm);
                    //nothing happens after this...
                    if(telephonyService.endCall()) {
                        Log.i("Debug", "Call ended...");
                    } else {
                        Log.i("Debug", "Call not ended...");
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                Log.i("Debug", "IDLE");
                break;
        }
    }
}

ITelephony.aidl

package com.android.internal.telephony;    
interface ITelephony {
    boolean endCall();
    void answerRingingCall();
    void silenceRinger();
}
Gowtham
  • 11,853
  • 12
  • 43
  • 64
  • Are you getting error like this "Error calling ITelephony#endCall"? Check the [source code](https://android.googlesource.com/platform/frameworks/base/+/android-5.0.0_r1/telephony/java/android/telephony/TelephonyManager.java) in case endCall is throwing RemoteException. – Tabrej Khan Jan 29 '15 at 14:13
  • No, I'm not getting anything. – Gowtham Jan 29 '15 at 14:16
  • 1
    As far as I can dig out endCall is not available after gingerbread i.e. 2.3 onwards. Here I can see you are using reflection to get ITelephony telephonyService object. **Still there are some solution given [over here](http://stackoverflow.com/questions/13080615/endcall-function-dosent-work) on SO. Give a try and test if it works for you.** – Tabrej Khan Jan 29 '15 at 14:26
  • Thanks for the reply. It do end the call, but the problem is I want to end the call when it is ringing or some time after the call has been attended. – Gowtham Jan 29 '15 at 15:07

3 Answers3

1

The last comment makes things unclear (In the question post).. "It do end the call, but the problem is I want to end the call when it is ringing or some time after the call has been attended."

So the call is ended but you want it to end while ringing or after some time ? 2 cases here: - While ringing: You need to check for CALL_STATE_RINGING and then go over to How to reject a call programatically android and check the techniques there

  • Some time after the call has been made: just call the method endCall() at a later stage from a Runnable (Or a different mechanism), you just postDelayed() on a handler and set some kind of delay time. In the code that runs in the Runnable I would check that the call is still ongoing

I'm probably off-mark, I suggest you clarify your comment/question

Community
  • 1
  • 1
Shai Levy
  • 715
  • 9
  • 25
  • Yeah, that's right. I need to end the call either while ringing or while the call has been attended. I will look into your solution about the **CALL_STATE_RINGING** and get you back. – Gowtham Feb 02 '15 at 10:22
  • You will not get CALL_STATE_RINGING in outgoing call in many phones. – maveroid Feb 02 '15 at 11:02
1

You are monitoring only for outgoing calls in your manifest. You can also monitor for phone state as well in manifest receiver.

Basically you want to end an outgoing call after few (e.g. 10) seconds of ringing or getting picked.

THERE IS NOT ANY WAY TO KNOW WHETHER AN OUTGOING CALL IS ANSWERED OR STILL RINGING since android does not send any update on this.

But since, you need to end an outgoing call only after few seconds your EndCallListener code should be like this:-

public class EndCallListener extends PhoneStateListener {
    Context context;
    TelephonyManager tm;
    public EndCallListener(Context context, TelephonyManager tm) {
        this.context = context;
        this.tm = tm;
    }
    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        switch (state) {
            case TelephonyManager.CALL_STATE_OFFHOOK:
                   handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Log.i("Debug", "OFFHOOK");   
                            try {
                                 Log.i("Debug", "Inside try...");
                                 Class c = Class.forName(tm.getClass().getName());
                                 Method m = c.getDeclaredMethod("getITelephony");
                                 ITelephony telephonyService = (ITelephony) m.invoke(tm);
                                 //nothing happens after this...
                                 if(telephonyService.endCall()) {
                                    Log.i("Debug", "Call ended...");
                                 } else {
                                    Log.i("Debug", "Call not ended...");
                                 }
                             } catch (ClassNotFoundException e) {
                                 e.printStackTrace();
                             } catch (NoSuchMethodException e) {
                                 e.printStackTrace();
                             } catch (InvocationTargetException e) {
                                 e.printStackTrace();
                             } catch (IllegalAccessException e) {
                                 e.printStackTrace();
                             } catch (RemoteException e) {
                                 e.printStackTrace();
                             }
                       }
                }, 10000);
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                Log.i("Debug", "IDLE");
                break;
        }
    }
}
maveroid
  • 1,840
  • 1
  • 20
  • 20
1

You can only detect when the phone starts to make an outgoing call and when the outgoing call is hunged up but you can't determine when a "ringing" is started.

The only workaround is to hang up after the outgoing call starts and passes for some seconds, but then, you're never guaranteed the phone will start ringing:

public class EndCallListener extends PhoneStateListener {
        int lastState = TelephonyManager.CALL_STATE_IDLE;
        boolean isIncoming;

    //Incoming call-   IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when hung up
    //Outgoing call-  from IDLE to OFFHOOK when dialed out, to IDLE when hunged up

    @Override
    public void onCallStateChanged(int state, String incomingNumber) {
        super.onCallStateChanged(state, incomingNumber);
        if(lastState == state){
            //No change
            return;
        }
        switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:
                isIncoming = true;
                 //incoming call started
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                //Transition of ringing->offhook are pickups of incoming calls.  Nothing down on them
                if(lastState != TelephonyManager.CALL_STATE_RINGING){
                    isIncoming = false;
                   //outgoing call started
             new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            Log.i("Debug", "OFFHOOK");   
                            try {
                                 Log.i("Debug", "Inside try...");
                                 Class c = Class.forName(tm.getClass().getName());
                                 Method m = c.getDeclaredMethod("getITelephony");
                                 ITelephony telephonyService = (ITelephony) m.invoke(tm);
                                 //nothing happens after this...
                                 if(telephonyService.endCall()) {
                                    Log.i("Debug", "Call ended...");
                                 } else {
                                    Log.i("Debug", "Call not ended...");
                                 }
                             } catch (ClassNotFoundException e) {
                                 e.printStackTrace();
                             } catch (NoSuchMethodException e) {
                                 e.printStackTrace();
                             } catch (InvocationTargetException e) {
                                 e.printStackTrace();
                             } catch (IllegalAccessException e) {
                                 e.printStackTrace();
                             } catch (RemoteException e) {
                                 e.printStackTrace();
                             }
                       }
                }, 10000);
                }
                break;
            case TelephonyManager.CALL_STATE_IDLE:
                //End of call(Idle).  The type depends on the previous state(s)
                if(lastState == TelephonyManager.CALL_STATE_RINGING){
                    // missed call
                }
                else if(isIncoming){
                      //incoming call ended
                }
                else{
                   //outgoing call ended                                              
                }
                break;
        }
        lastState = state;
    }

}

}

Nana Ghartey
  • 7,901
  • 1
  • 24
  • 26