Android Froyo: my life with call_log

1.3k views Asked by At

I'm stuck with the call_log functionality in Froyo. As many of you know, Froyo logs in call log not only calls but also each outgoing and incomming SMS message. You can chose in options to show all that crap, or only specific types (outgoing calls, incoming calls, sent messages, received messages etc), but since this is radio button, you cannot specify for example only ongoing and incoming calls. Very known and annoing Froyo functionality.

So I started to write some simple tool to read the call log by myself. Here is the code snippet:

try {
    mCur = getApplicationContext().getContentResolver()
               .query(CallLog.Calls.CONTENT_URI, columns, null, null, null );
    mCur.moveToFirst();
    io = mCur.getColumnIndex(CallLog.Calls._ID);
    bo = mCur.getColumnIndex(CallLog.Calls.NUMBER);
    no = mCur.getColumnIndex(CallLog.Calls.CACHED_NAME);
    to = mCur.getColumnIndex(CallLog.Calls.TYPE);

    while (mCur.isAfterLast() == false) {
        i = mCur.getString(io);
        b = mCur.getString(bo);
        n = mCur.getString(no);
        t = mCur.getString(to);
        Log.i(TAG, "CallLog: ID="+i+" number="+b+" name="+n+" type="+t);

        mCur.moveToNext();
    }
} catch (Exception e) {
    Log.e(TAG, "updateCallLog", e);
} finally {
    if (mCur != null) {
        mCur.close();
        mCur = null;
    }
}

Surprise, surprise, the call_log provider skips the sms records from the call log. So with the code above I see only call records (incoming or outgoing), all other records are skipped. The little more digging into it revealed that the CallLog provider adds internally filtering to the call log database:

02-03 09:26:42.348 E/CLCService(28244): android.database.sqlite.SQLiteException: 
near ")": syntax error: , while compiling: 
SELECT _id, name, number, type FROM logs WHERE (logtype=100 OR logtype=500) AND (_ID=)

Do not look for the syntax error, it was created on purpose to force provider to dump the SQL query by calling query(CallLog.Calls.CONTENT_URI, columns, "_ID=", null, null )). The (_ID=) is what is provided in the query, the rest of (logtype=100 OR logtype=500) is apparently added by the call log provider itself.

So I have two questions:

  1. Where I can find in the Android code how the provider is adding the logtype filter? I was looking into CallLog.java and CallLogProvider.java and cannot find it.
  2. How can I read all records from the call log in Froyo? I cannot bypass the call log provider and use my own SQL helper for this until I will not root the phone, which is not an option. Is there any other way to do it?
1

There are 1 answers

0
patthoyts On

I'm not certain just what is going wrong but reading the call log to get just incoming or outgoing calls is simple enough. The sample below adds restrictions to the query so that it only returns data for outgoing calls made after a certain date. The where string uses question marks to indicate where the values from the wargs array should be substituted in to form the sql query.

About where the extra WHERE clause occurs. Almost certainly in the calllog provider implementation. The providers commonly have a switch statement that uses the uri that you use to open the provider and then adds restrictions based on the uri. The calllog one seems to be in packages/providers/ContactsProvider.

public static int getMinutesUsedSince(Context context, Date date) {
    Uri uri = CallLog.Calls.CONTENT_URI;
    String columns[] = new String[] { CallLog.Calls.DURATION };
    String where = CallLog.Calls.TYPE + "=? AND " + CallLog.Calls.DATE + ">?";
    String wargs[] = new String[] {
            String.valueOf(CallLog.Calls.OUTGOING_TYPE),
            String.valueOf(date.getTime())
    };
    String sortOrder = "date DESC";
    Cursor c = context.getContentResolver().query(uri, columns, where, wargs, sortOrder);
    long sum = 0;
    int durationIndex = c.getColumnIndex(CallLog.Calls.DURATION);
    if (c.moveToFirst()) {
        do {
            /* for each individual call, round up to the nearest minute */
            long duration = c.getLong(durationIndex);
            long minutes = (long)Math.ceil(duration / 60.0);
            sum += minutes;
        } while (c.moveToNext());
    }
    c.close();
    return (int)sum;
}