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
good work
ReplyDeleteThis comment has been removed by the author.
ReplyDeletelogcat Error:
ReplyDelete05-29 22:01:12.180 13207-13207/com.prodip.phonehistory E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.CallLogProvider from ProcessRecord{41da19e0 13207:com.prodip.phonehistory/10153} (pid=13207, uid=10153) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
at android.os.Parcel.readException(Parcel.java:1327)
at android.os.Parcel.readException(Parcel.java:1281)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:2298)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:4041)
at android.app.ContextImpl$ApplicationContentResolver.acquireProvider(ContextImpl.java:1771)
at android.content.ContentResolver.acquireProvider(ContentResolver.java:918)
at android.content.ContentResolver.query(ContentResolver.java:305)
at com.prodip.phonehistory.History.getCalldetailsNow(History.java:46)
at com.prodip.phonehistory.History.onChange(History.java:38)
at android.database.ContentObserver$NotificationRunnable.run(ContentObserver.java:43)
at android.os.Handler.handleCallback(Handler.java:605)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4517)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)
show following line error when i check by call by my device :
ReplyDelete"Cursor managedCursor=c.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, android.provider.CallLog.Calls.DATE + " DESC");"
and unfortunately stop the app
requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS, add those permissions in your manifest file.
Deleteshowing no history exists
ReplyDeleteIts working Bro.
DeleteNot Showing any history Worst !
ReplyDeleteGetting any error?
Deletehave some problm sir
ReplyDeletePlease post you problem.
DeleteHi, I have a questios about broadcast receiver. How can ı dedect call when it is anwered. when i look examples ı found that listener "CALL_STATE_IDLE,CALL_STATE_OFFHOOK".
ReplyDeleteBest Regards,
Mehmet
All details are given above and Call state offhook is called when user is on call.
Deletebagaimana cara mengetahui bahwa telepon sudah terhubung pada saat pengguna menggunakan pemanggilan telepon keluar ?
DeleteHi, how could I do to read call log only for one contact (for this contact, I know id, name and phone numbers) ?
ReplyDeleteThis comment has been removed by the author.
ReplyDelete(ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG) == PackageManager.PERMISSION_GRANTED)
ReplyDeleteerror in this wrong argument found
sir when i copy this code i got error in MainActivity.java
ReplyDeletepublic 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;
}
IN THE ABOVE CODE I GOT ERROR IN .menu
if (id == R.id.action_settings) {
db.deleteTable();
tv.setText("No Incoming and Outgoing call history exists!!!");
return true;
}
AND IN THE ABOVE CODE I GOT ERROR IN action_settings
for me also when i run the code it shows that "NO INCOMING AND OUTGOING CALL HISTORY EXISTS"
ReplyDeletePlease grand permission for your app
DeleteHad you resolved the issue ?
ReplyDeletepada pemanggilan telepon keluar berlangsung dan klik untuk menyelesaikan panggilan. maka bagaimana caranya untuk mengetahui durasi panggilan tersebut ?
ReplyDeleteThank you so much...
ReplyDeletesir i have error no incoming and outgoing call exists!!!
ReplyDeleteThanks a lot for this code! It's working correctly but I am able to detect incoming and missed calls. The outgoing calls are not getting detected. What might be the reason or solution for it?
ReplyDeleteis we have to call the call Intent firstly??? to detect incoming outgoing call?
Deleteit's showing no incoming and outgoing calls..how should i get the history as you shown?
ReplyDeletehow can I get the calls logs if the app is killed or removed from the stack.?
ReplyDelete