Android - How to detect outgoing call is answered or received?

风流意气都作罢 提交于 2019-12-03 03:48:26
Mohammad Qandeel

After deeply working on this issue, I reached this conclusion:

  1. PhoneStateListener won't work for outgoing calls, it calls OFFHOOK instead of RINGING and OFFHOOK is never called on ANSWER.

  2. Using NotificationListenerService, you can listen to posted notifications related to outgoing calls. You can do something like the below code. The issue here is that I'm not able to get the notification text from some Samsung phones, also the text itself might change a lot from one phone to another. Also it requires API 18 and above.

    public class NotificationListener extends NotificationListenerService {
    
        private String TAG = this.getClass().getSimpleName();
    
        @Override
        public void onNotificationPosted(StatusBarNotification sbn) {
            Log.i(TAG, "Notification Posted");
            Log.i(TAG, sbn.getPackageName() +
                    "\t" + sbn.getNotification().tickerText +
                    "\t" + sbn.getNotification().extras.getString(Notification.EXTRA_TEXT);
    
            Bundle extras = sbn.getNotification().extras;
    
            if ("Ongoing call".equals(extras.getString(Notification.EXTRA_TEXT))) {
                startService(new Intent(this, ZajilService.class).setAction(ZajilService.ACTION_CALL_ANSWERED));
            } else if ("Dialing".equals(extras.getString(Notification.EXTRA_TEXT))) {
                startService(new Intent(this, ZajilService.class).setAction(ZajilService.ACTION_CALL_DIALING));
            }
        }
    
        @Override
        public void onNotificationRemoved(StatusBarNotification sbn) {
            Log.i(TAG, "********** onNotificationRemoved");
            Log.i(TAG, "ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText + "\t" + sbn.getPackageName());
        }
    }
    
  3. Using AccessibilityService, it is more basic than NotificationListenerService and I think it is supported by all APIs. But also using AccessibilityService, some phones don't publish useful events in case of call Answer. In most phones, an event wil be raised once the call answered, with call duration; Its printout looks like this:

onAccessibilityEvent EventType: TYPE_WINDOW_CONTENT_CHANGED; EventTime: 21715433; PackageName: com.android.incallui; MovementGranularity: 0; Action: 0 [ ClassName: android.widget.TextView; Text: []; ContentDescription: 0 minutes 0 seconds;

onAccessibilityEvent EventType: TYPE_WINDOW_CONTENT_CHANGED; EventTime: 21715533; PackageName: com.android.incallui; MovementGranularity: 0; Action: 0 [ ClassName: android.widget.TextView; Text: []; ContentDescription: 0 minutes 1 seconds;

  1. API 23 has a new class, Call. it has more detailed call states; STATE_ACTIVE. You can replace the default InCallUI of the phone by your own UI through InCallService I didn't try to use this yet, but anyway, it is just limited to API 23, Marshmallow.

As a conclusion, You need to build a solution combined with NotificationListener and AccessibilityService, in order to cover all phone, hopefully.

Neo

You need to use a combination of RINGING state and OFFHOOK state to figure out if the call is answered.

See this thread for actual code on how to achieve this.

I know its been a while but i hope to be helpful for someone still looking for a solution!

I recently had to work on a similar project where i needed to capture the ringing state of an outgoing call and the only way i could find was using the hidden Api of native dial-up App. This would only be possible for android > 5.0 because of the api changes. This was tested on Android 5.0.1, and worked like a charm. (p.s. you would need a rooted device for it to work, because you need to install your app as a System application (google how!) which will then be able to detect the outgoing call states).

For the record, PhoneStateListener doesn't work for detecting the outgoing call states as mentioned in many posts.

First, add this permission in the manifest file,

<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />

Then define you broadcastreceiver, (here is a sample code!)

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;

public class MyBroadcastReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, final Intent intent)
    {
        switch (intent.getIntExtra("foreground_state", -2)) {
            case 0: //  PreciseCallState.PRECISE_CALL_STATE_IDLE:
                System.out.println("IDLE");
                break;
            case 3: //  PreciseCallState.PRECISE_CALL_STATE_DIALING:
                System.out.println("DIALING");
                break;
            case 4: //  PreciseCallState.PRECISE_CALL_STATE_ALERTING:
                System.out.println("ALERTING");
                break;
            case 1: //  PreciseCallState.PRECISE_CALL_STATE_ACTIVE:
                System.out.println("ACTIVE");
                break;
        }

    }
} 

I replaced some of the constants with their values because i saw a lot of confusion among the folks unfamiliar with the concept of reflection (so for ease). Alerting is basically the state when receiver is actually ringing! and that does not include the call setup time which means that the call has been received successfully!. There are other options in precise_call_state class (which i didn't explore), to help you with capturing the call being answered!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!