Home » Android » Detecting outgoing call answered on Android

Detecting outgoing call answered on Android

Posted by: admin May 14, 2020 Leave a comment

Questions:

I know this has been asked many times already, with no answers, but I still hope that someone has finally solved the problem.

The problem: I have a non-rooted device running Android 2.3. I need to create a service which:

  1. makes a phone call;
  2. waits until the call is answered;
  3. hangs the phone after the call is answered (with a timeout);

Like many others, I’ve got stuck with #2. Below is the summary of the solutions ever suggested:

  • Use PhoneStateListener (most popular): does not work, for an outgoing call it cannot detect what I need.
  • Use com.android.internal.telephony.CallManager and its methods like registerForPreciseCallStateChanged (e.g., this one): does not work, no phones are registered within it, so the events do not fire.
  • Use com.android.internal.telephony.PhoneFactory to obtain a com.android.internal.telephony.Phone instance (which is the key to everything): does not work, the factory is not initialized; attempts to initialize it with a makeDefaultPhones call result in a security exception (like here).
  • Detect the outgoing ringtone (link): the author – Dany Poplawec – states that detecting ringtones may help to solve the problem, but does not provide any details, so I was not able to try this technique.

It looks like everything has been tried already, but there still may be one more trick that will save me 🙂

How to&Answers:

I’m trying to get this too and can’t find any solution yet.

Looking on the Android Source Code I found these lines in ~/kitchen/jellybean/frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java

public enum State {
    IDLE, ACTIVE, HOLDING, DIALING, ALERTING, INCOMING, WAITING, DISCONNECTED, DISCONNECTING;

    public boolean isAlive() {
        return !(this == IDLE || this == DISCONNECTED || this == DISCONNECTING);
    }

    public boolean isRinging() {
        return this == INCOMING || this == WAITING;
    }

    public boolean isDialing() {
        return this == DIALING || this == ALERTING;
    }
}

I think one could know if an outgoing call was answered checking the ACTIVE state, but I don’t know how to read this value from an app, maybe modifying the framework by adding a specific function for this like:

    public boolean isActive() {
         return this == ACTIVE;
    }

This is just an idea, but I’m not sure how to implement this, because obviously other modifications have to be done for accessing this new function from the application layer.

If you find this viable or know how to do it, help and feedback will be very appreciated.

Answer:

The solution in your 3rd bullet should be possible in rooted devices, if you follow the instructions in Android INJECT_EVENTS permission

Step by step, it is something like:

  1. Signing the app with the platform certificate. This requires the following steps:
    • add android:sharedUserId=”android.uid.phone” to the manifest-tag of your apk´s manifest.
    • add android:process=”com.android.phone” to the application-tag of the manifest.
    • you may need to add a few extra permissions to your manifest, and will also need to change the severity for ProtectedPermission in the “Android Lint Preferences” of your project.
    • get the platform.pk8 + platform.x509.pem from {Android Source}/build/target/product/security (I have used the ones for 4.4.4r1 in https://android.googlesource.com/platform/build/+/android-4.4.4_r1/target/product/security/)
    • Download keytool-importkeypair from https://github.com/getfatday/keytool-importkeypair
    • Use this script to obtain the keystore for the platform with command: keytool-importkeypair -k google_certificate.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform . I ran it on cygwin, with a minor modification of the script.
    • Sign the apk using this keystore.
  2. install the application as a system app using adb:

    adb root

    adb remount

    adb push MyApp.apk /system/app

    adb shell chmod 644 /systen/app/MyApp.apk

  3. Restart the device.

I have actually tried the solution in the 2nd bullet and it does not work for me either (on a Galaxy S5 running Kitkat).
The solution in the 3rd bullet item does work quite OK. Regardless of the package name, the app runs as com.android.phone , so you need to attach to that process if you want to debug the app.