Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Android Call log details after ending call using ContentObserver & PhoneStateListener

This android tutorial will cover below questions:

1. How to get incoming call number in android (Broadcast receiver for incoming number)?
2. How to get outgoing call number in android (Broadcast receiver for outgoing number)?
3. How to know call is ended or not in android?
4. How to get call log details after ending call in android?
5. How to create and use SQLite Data Base in android?
6. How to fire Content Observer after ending call?


I had worked a lot with phone state and spend time and money to know what exactly android doing. Now I am here with working code and going to share with all coders.

I am using broadcast receiver to know state of the phone and get incoming and outgoing number. Phone has three states:

1. Ringing: call is coming.
2. Idle: inactive or call disconnected.
3. Offhook: active state.

We can easily detect phone state and can know when call is ending using idle state and get new call log details but we can face any problems which are listing below:

1. Idle state call once again after idle state sometime (or in some device).
2. Idle state call in between Offhook state sometime (or in some device).
3. Call ended but call log not created yet and we queried to fetch new call log information and get wrong result sometime.

Hmm… Problems can create new problem(s). But After lot of research, finally I solved all the problems and used Content Observer to keep track on changes in call logs and use if condition to solve call end problem. Now Content Observer is creating a new problem and calling many times and giving single and exact call details multiple times. Using if condition this problem is also solved.



I used simple XML layout to show call log details: your_project -> res -> layout -> activity_main.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollView1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Large Text"
android:textAppearance="?android:attr/textAppearanceLarge" />

</ScrollView>

Now i used 4 Java files:-

1. MainActivity.java : To display result.

package com.example.phonehistory;

import android.support.v7.app.ActionBarActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;


public class MainActivity extends ActionBarActivity {

DBHelper db;
TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView)findViewById(R.id.text);
tv.setText("");

db=new DBHelper(this, "ZnSoftech.db", null, 2);

Cursor c=db.getData();

if(c.getCount()>0)
{
c.moveToFirst();
do
{
String number=c.getString(0);
String date=c.getString(1);
String time=c.getString(2);
String duration=c.getString(3);
String type=c.getString(4);

tv.append("Number:"+number+"\nDate:"+date+"\nTime:"+time+"\nDuration:"+duration+"\nCall Type:"+type+"\n\n");
}while(c.moveToNext());
}
else
{
tv.setText("No Incoming and Outgoing call history exists!!!");
}

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
db.deleteTable();
tv.setText("No Incoming and Outgoing call history exists!!!");
return true;
}
return super.onOptionsItemSelected(item);
}
}

2. PhListener.java : To listen phone state.

package com.example.phonehistory;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.provider.CallLog;
import android.telephony.TelephonyManager;

@SuppressLint("SimpleDateFormat") public class PhListener extends BroadcastReceiver{

@Override
public void onReceive(Context c, Intent i) {
// TODO Auto-generated method stub
Bundle bundle=i.getExtras();

if(bundle==null)
return;

SharedPreferences sp=c.getSharedPreferences("ZnSoftech", Activity.MODE_PRIVATE);

String s=bundle.getString(TelephonyManager.EXTRA_STATE);

if(i.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL))
{
String number=i.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
sp.edit().putString("number", number).commit();
sp.edit().putString("state", s).commit();
}

else if(s.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
String number=bundle.getString("incoming_number");
sp.edit().putString("number", number).commit();
sp.edit().putString("state", s).commit();
}

else if(s.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
sp.edit().putString("state", s).commit();
}

else if(s.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
String state=sp.getString("state", null);
if(!state.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
sp.edit().putString("state", null).commit();
History h=new History(new Handler(),c);
c.getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, true, h);
}
sp.edit().putString("state", s).commit();
}

}

}

3. DBHelper.java : To store call log details in database.

package com.example.phonehistory;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper{

public DBHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
// TODO Auto-generated constructor stub
}

@Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
db.execSQL("create table if not exists call_history(number varchar, date varchar, time varchar, duration varchar, type varchar)");
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS call_history");
onCreate(db);
}

public boolean insertdata(String number, String date, String time,String duration, String type)
{
SQLiteDatabase sdb=this.getWritableDatabase();
sdb.execSQL("insert into call_history values('"+number+"','"+date+"','"+time+"','"+duration+"','"+type+"')");
return true;
}

public Cursor getData()
{
SQLiteDatabase sdb=this.getReadableDatabase();
Cursor c=sdb.rawQuery("select * from call_history", null);
return c;
}
public void deleteTable()
{
SQLiteDatabase db=this.getWritableDatabase();
db.execSQL("DROP TABLE IF EXISTS call_history");
onCreate(db);
}

}


4. History.java : To fire content observer to keep track on changes in call log.

package com.example.phonehistory;

import java.text.SimpleDateFormat;
import java.util.Date;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.provider.CallLog;

@SuppressLint("SimpleDateFormat")
public class History extends ContentObserver {

Context c;

public History(Handler handler, Context cc) {
// TODO Auto-generated constructor stub
super(handler);
c=cc;
}

@Override
public boolean deliverSelfNotifications() {
return true;
}

@Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
SharedPreferences sp=c.getSharedPreferences("ZnSoftech", Activity.MODE_PRIVATE);
String number=sp.getString("number", null);
if(number!=null)
{
getCalldetailsNow();
sp.edit().putString("number", null).commit();
}
}

private void getCalldetailsNow() {
// TODO Auto-generated method stub

Cursor managedCursor=c.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, android.provider.CallLog.Calls.DATE + " DESC");

int number = managedCursor.getColumnIndex( CallLog.Calls.NUMBER );
int duration1 = managedCursor.getColumnIndex( CallLog.Calls.DURATION);
int type1=managedCursor.getColumnIndex(CallLog.Calls.TYPE);
int date1=managedCursor.getColumnIndex(CallLog.Calls.DATE);

if( managedCursor.moveToFirst() == true ) {
String phNumber = managedCursor.getString(number);
String callDuration = managedCursor.getString(duration1);

String type=managedCursor.getString(type1);
String date=managedCursor.getString(date1);

String dir = null;
int dircode = Integer.parseInt(type);
switch (dircode)
{
case CallLog.Calls.OUTGOING_TYPE:
dir = "OUTGOING";
break;
case CallLog.Calls.INCOMING_TYPE:
dir = "INCOMING";
break;
case CallLog.Calls.MISSED_TYPE:
dir = "MISSED";
break;
default:
dir = "MISSED";
break;
}

SimpleDateFormat sdf_date = new SimpleDateFormat("dd/MM/yyyy");
SimpleDateFormat sdf_time = new SimpleDateFormat("h:mm a");
// SimpleDateFormat sdf_dur = new SimpleDateFormat("KK:mm:ss");

String dateString = sdf_date.format(new Date(Long.parseLong(date)));
String timeString = sdf_time.format(new Date(Long.parseLong(date)));
// String duration_new=sdf_dur.format(new Date(Long.parseLong(callDuration)));

DBHelper db=new DBHelper(c, "ZnSoftech.db", null, 2);
db.insertdata(phNumber, dateString, timeString, callDuration, dir);

}

managedCursor.close();
}

}

Now change AndroidManifast.xml file and define all necessary permissions.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.phonehistory"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.phonehistory.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<receiver android:name="com.example.phonehistory.PhListener" >
<intent-filter
android:priority="-1">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>

</application>

</manifest>

Now run your code and check android project. If you have any problems feel free to ask me. Share if you like this post and don’t forget to leave valuable comment regarding call log details android post or this website. Github link of this project: Android Call Log Details

Related Tutorials:

1. Access Call, Camera, Web pages
2. Use SQLite Database
3. Use Shared Preferences
4. Print numbers from 1 to 100 in ScrollView
5. Create Menu using XML


This post first appeared on Coders Hub: Android Code Examples And Programming Tutorials, please read the originial post: here

Share the post

Android Call log details after ending call using ContentObserver & PhoneStateListener

×

Subscribe to Coders Hub: Android Code Examples And Programming Tutorials

Get updates delivered right to your inbox!

Thank you for your subscription

×