Sunday, August 14, 2011

Android outgoing call interception

An android App can alter outgoing calls by creating a BroadcastReceiver to intercept the ACTION_NEW_OUTGOING_CALL intent and set the resultData to the new number to be called (or null in order to cancel the call). Some example code:
public class CallReceiver extends BroadcastReceiver
{
    public void onReceive(Context context, Intent intent)
    {
        String dialedNumber = intent.getStringExtra(
            Intent.EXTRA_PHONE_NUMBER);

        // do some useful conversion on the dialed number
        String correctedNumber = correctNumber(dialedNumber);

        setResultData(correctedNumber);
    }
}
Unfortunately, some handsets seem to completely ignore the new phone number passed to setResultData so software relying on this function does not work.

What I have done in IntlPrefix to workaround this issue is to cancel the current call, and then make a new one. Below is the new code:
public class CallReceiver extends BroadcastReceiver
{
    public void onReceive(Context context, Intent intent)
    {
        String dialedNumber = intent.getStringExtra(
            Intent.EXTRA_PHONE_NUMBER);
        String correctedNumber = correctNumber(dialedNumber);
        if(useAlternateMethod())
        {
            // Cancel current call and make a new one on (buggy)
            // phones that ignore call to setResultData
            setResultData(null);
            Intent callIntent = new Intent(Intent.ACTION_CALL,
                Uri.parse("tel:" + correctedNumber));
            callIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(callIntent);
        }
        else
        {
            // All other models: just setResultData to the new
            // phone number
            setResultData(correctedNumber);
        }
    }
useAlternateMethod returns true on "broken" phone models, indicating the workaround must be used (I keep adding models as my users report IntlPrefix does not work on their phones):
    private boolean useAlternateMethod()
    {
        String product = android.os.Build.PRODUCT;
        int sdk_int = android.os.Build.VERSION.SDK_INT;
        return
            // HTC Desire on Android 2.2
            (product.equals("htc_bravo") && sdk_int == 8)
            // HTC Desire S on Android 2.3.3
            || (product.equals("htc_saga") && sdk_int == 10)
            // HTC Wildfire S on Android 2.3.3
            || (product.equals("htc_marvel") && sdk_int == 10)
            ;
    }
}
Note that due to this alternate method, your App will now need the CALL_PHONE permission. But well, that's life.

Hope this information is useful for other Android developers out there.

4 comments:

  1. Hello,

    Did you try to write the Receiver and ItentFilter into AndroidManifest.xml ?

    I tried and it works.

    ReplyDelete
    Replies
    1. Hi Thiagoturim,

      Of course I have already done that (see http://code.google.com/p/intlprefix/source/browse/trunk/intlprefix/AndroidManifest.xml).

      However, that does not change anything, unfortunately

      Delete
  2. Hi Gaston,

    I am stuck with the same problem, thanks for this post.

    Why aren't you using the alternate method for all the devices. Is it something we shouldn't do ?

    ReplyDelete
    Replies
    1. Tough call but I prefer to stick with "official" method, otherwise we are accepting that handset makers do whatever they want with the standard...

      Delete