10

When a call ends, how can I be sure that I am querying the Call Log after the call information has been written to the database?

I am looking for the end of a call by using a BroadcastReceiver with an intent-filter on android.intent.action.PHONE_STATE , looking for the phone to go idle .

Any help on this would be appreciated.

Thanks

Dharmendra
  • 33,296
  • 22
  • 86
  • 129
gnub
  • 189
  • 5
  • 11

1 Answers1

9

Here is the very very good answer.

See below link

Click Here

When you see above example you will learn how to get call's end-state and you will also keep in mind that after call ends CALL_STATE_IDLE will calls more than once so you have to take one static variable in some where and you have to check that variable value before you work in ideal state.

EDIT

Android stores call log information in its inbuilt database. So better solution is that when your code calls IDLE state after OFFHOOK state then you can copy all newly call log from inbuilt database to your database for get information of call log

You can retrieves call-log information from inbuilt database using following query

Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, null, null, null, null);

EDIT2

Here is complete example

This is PhoneStateListener class

public class CustomPhoneStateListener extends PhoneStateListener {

Context context;
public CustomPhoneStateListener(Context context) {
super();
this.context = context;
}

@Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);

switch (state) {
    case TelephonyManager.CALL_STATE_IDLE:
        // Toast.makeText(context, "CALL_STATE_IDLE", Toast.LENGTH_LONG).show();
        if(UDF.phoneState != TelephonyManager.CALL_STATE_IDLE) {
            UDF.fetchNewCallLogs(context);
        } 
        break;
    case TelephonyManager.CALL_STATE_OFFHOOK:
         //Toast.makeText(context, "CALL_STATE_OFFHOOK", Toast.LENGTH_LONG).show();
        break;
    case TelephonyManager.CALL_STATE_RINGING:
         //Toast.makeText(context, "CALL_STATE_RINGING", Toast.LENGTH_LONG).show();
        endCallIfBlocked(incomingNumber);
        break;

    default:
        break;
}
UDF.phoneState = state;
}

This is broadcast receiver class

public class PhoneStateBroadcastReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        //UDF.createTablesIfNotExists(context);
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        telephonyManager.listen(new CustomPhoneStateListener(context), PhoneStateListener.LISTEN_CALL_STATE);
    }
}

This is function for get new call logs from internal database

public static void fetchNewCallLogs(Context context) {

        CallLogHelper callLogHelper = new CallLogHelper(context);
        callLogHelper.open();
        Long maxId = callLogHelper.getMaxId();

        Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, null, "_id > ?", new String[]{String.valueOf(maxId)}, null);
        if(c != null && c.moveToFirst()) {
            while (c.isAfterLast() == false) {
                int _ID = c.getColumnIndex(android.provider.CallLog.Calls._ID);
                int _NUMBER = c.getColumnIndex(android.provider.CallLog.Calls.NUMBER);
                int _DATE =  c.getColumnIndex(android.provider.CallLog.Calls.DATE);
                int _DURATION =  c.getColumnIndex(android.provider.CallLog.Calls.DURATION);
                int _CALLTYPE =  c.getColumnIndex(android.provider.CallLog.Calls.TYPE);
                int _NAME =  c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME);
                int _NUMBERTYPE =  c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NUMBER_TYPE);
                int _NEW = c.getColumnIndex(android.provider.CallLog.Calls.NEW);

                String id = c.getString(_ID);
                String number = c.getString(_NUMBER);
                String date = c.getString(_DATE);
                String duration = c.getString(_DURATION);
                String callType = c.getString(_CALLTYPE);
                String name = c.getString(_NAME);
                String numberType = c.getString(_NUMBERTYPE);
                String _new = c.getString(_NEW);

                callLogHelper.createLog(id, number, date, duration, callType, name, numberType, _new, "N");

                c.moveToNext();
            }
        }
        callLogHelper.close();
    }


**Where** 


 => CallLogHelper is a helper class to communicate with my local database
    => callLogHelper.getMaxId(); will returns the maximum id of call logs in my local database and I am keeping the id in local database and internal database will be same
    => callLogHelper.createLog() is my function to insert call log in my local database

This is manifest file

<receiver android:name=".PhoneStateBroadcastReceiver">
<intent-filter>
    <action android:name="android.intent.action.PHONE_STATE"/>     
</intent-filter>
</receiver>
Community
  • 1
  • 1
Dharmendra
  • 33,296
  • 22
  • 86
  • 129
  • Thank you for your response. How would you query `CallLog.Calls.CONTENT_URI` from the `PhoneStateListener`? Does this solution address the race condition that typically presented when querying `CallLog.Calls.CONTENT_URI` after the phone state changes? – gnub Aug 31 '11 at 00:36
  • 5
    Correct. The problem I have is that sometimes the `BroadCastReceiver` fires before the CallLog has been updated, so when you query `android.provider.CallLog.Calls.CONTENT_URI`, you're missing the most recent call. – gnub Sep 02 '11 at 00:27
  • Not exactly broadcast receiver will call when new call comes or outgoing calls and also broadcast receiver will call more than two times so you have to check in which situation you have to query on content_uri for get recent value – Dharmendra Sep 02 '11 at 03:39
  • I don't disagree with what you're saying. However, your responses do not address my question. – gnub Sep 08 '11 at 01:43
  • I have put small example to copy internal call log to your local database – Dharmendra Sep 08 '11 at 03:59
  • Does anyone know what does google understand by "recent" calls? They mean the last 2 months/1 year or what? – erdomester Oct 10 '11 at 07:45
  • 1
    @gnub When your phone state go to ideal to off_hook and again off_hook to ideal state means that your call is now end and at that time you can query on Internal database to retrieves new call log.You can keep tract by storing the exact same row id as in Internal database so that you can query on database to get call log greater than the last row id – Dharmendra Oct 11 '11 at 03:37
  • yes, but if you query before the latest call information has been written, then your query will not return any results. – gnub Oct 17 '11 at 02:20
  • After phone_state changed to off_hook to idle state call entry will be written and if you will execute query on call log database it will return a new call log in the list. – Dharmendra Oct 17 '11 at 03:43
  • 3
    @gnub : did u find a solution to handle this race condition. I am facing the same issue. Thanks a lot – png Jun 04 '12 at 08:05
  • @Dharmendra How to stop call log screen right after the call end? any idea?. – Mohammed Azharuddin Shaikh Jun 05 '12 at 06:01
  • 5
    @gnub: You're right, I ended up on this question while searching for a solution to the problem you mentioned. As a temporary and really ugly fix, I replaced the equivalent of your call to `fetchNewCallLogs()` with the creation and call to `start()` of a new thread, which simply sleeps for 500ms and then calls `fetchNewCallLogs()`. – Riccardo T. Jul 13 '13 at 17:17
  • 1
    What is UDF?? Can anyone explain? – Md Mohsin Dec 10 '14 at 05:23
  • His Local Sql Lite Db class object – FGH Jul 21 '20 at 18:50
  • @Dharmendra thank you for your explanation. I run the same app in the Huawei I get the expected output, but if I run the app in the Samsung, I'm getting oldest call log, What I want to do now? – FGH Jul 26 '20 at 13:07