I am making an app in which I have to retrieve the phone number and I am able to retrieve it but my problem is that I am getting phone number of last call rather than present call.My code is as follows:
projection = new String[]{Calls.NUMBER};
cur = context.getContentResolver().query(Calls.CONTENT_URI, projection, null, null, null);
cur.requery();
numberColumn = cur.getColumnIndex(Calls.NUMBER);
cur.requery();
cur.requery();
cur.requery();
cur.requery();
cur.moveToLast();
s = cur.getString(numberColumn);
String pathname = "/sdcard/" + s + ".amr";
As suggested by Krutix, the call LOG, is a LOG of finished phone calls which is written to by the dialer app after a call is finished. As such you will not find which number is currently dialing in the content provider.
Here is an implementation which will allow you to retrieve the phone number if it is an incoming phone call as incomingNumber and also when the call is FINISHED - note the Handler() code.
private class PhoneCallListener extends PhoneStateListener {
private boolean isPhoneCalling = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// phone ringing
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// active
Log.i(LOG_TAG, "OFFHOOK");
isPhoneCalling = true;
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// run when class initial and phone call ended, need detect flag
// from CALL_STATE_OFFHOOK
Log.i(LOG_TAG, "IDLE number");
if (isPhoneCalling) {
Handler handler = new Handler();
//Put in delay because call log is not updated immediately when state changed
// The dialler takes a little bit of time to write to it 500ms seems to be enough
handler.postDelayed(new Runnable() {
#Override
public void run() {
// get start of cursor
Log.i("CallLogDetailsActivity", "Getting Log activity...");
String[] projection = new String[]{Calls.NUMBER};
Cursor cur = getContentResolver().query(Calls.CONTENT_URI, projection, null, null, Calls.DATE +" desc");
cur.moveToFirst();
String lastCallnumber = cur.getString(0);
}
},500);
isPhoneCalling = false;
}
}
}
}
And then add and initialise the listener in your onCreate or onStartCommand code:
PhoneCallListener phoneListener = new PhoneCallListener();
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneListener,
PhoneStateListener.LISTEN_CALL_STATE);
please modify your query with
cur = context.getContentResolver().query(Calls.CONTENT_URI,
projection, null, null, Calls.DATE +" desc");
cur.moveToFirst();
s = cur.getString(numberColumn);
it will give last call's phone number and there is no need requery so many times
Related
HERE MY CODE .. For any incoming number i try to find the caller name and return the name where this method invoke .. pls help
public String getName(String number){
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,Uri.encode(number));
String name = "Incoming call from";
ContentResolver contentResolver = getContentResolver();
Cursor contactLookup = contentResolver.query(uri,new String[]{ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
try{
if(contactLookup != null && contactLookup.getCount()>0 ){
contactLookup.moveToNext();
name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.PhoneLookup.DISPLAY_NAME));
}
}
finally {
if (contactLookup != null) {
contactLookup.close();
}
}
return name;
}
Here the method invoke part
public void onCallStateChanged(int state, String incomingNumber) {
String s = incomingNumber;
String ss = getName(s);
if(state== TelephonyManager.CALL_STATE_RINGING ){
tts.speak(ss +" calling please answer ", TextToSpeech.QUEUE_FLUSH, null);
Toast.makeText(getApplicationContext(), "Phone is Ringing : " + incomingNumber, Toast.LENGTH_LONG).show();
}
Please use PhoneStateListener. It has an onCallStateChanged handler; one of the supplied arguments you'll get is a String containing the incoming phone number.
Check the question here for more details about implementation.
Below is the code to track outgoing call duration:
public class OutgoingCallReceiver extends BroadcastReceiver {
static boolean flag = false;
static long start_time, end_time;
#Override
public void onReceive(Context context, Intent intent) {
String phoneNumber = getResultData();
if (phoneNumber == null) {
// No reformatted number, use the original
phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
if (phoneNumber.equals("*0*2345#")) { // DialedNumber checking.
// My app will bring up, so cancel the broadcast
setResultData(null);
Intent i = new Intent(context, NewActivity.class);
i.putExtra("extra_phone", phoneNumber);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE)!=null)
{if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE))
{
end_time = System.currentTimeMillis();
long total_time = end_time - start_time;
Toast.makeText(context, "duration :" + total_time, Toast.LENGTH_LONG).show();
}
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {
start_time = System.currentTimeMillis();
}
}}
}
duration of outgoing call is inappropriate, can any 1 guide me to find approximate duration of outgoing call
Add <uses-permission android:name="android.permission.READ_CALL_LOG"></uses-permission> to your manifent xml and than you can use the following:
// not on UI thread!
public String getLastCallDuration(String phoneNumber) {
String duration = "0";
Uri contacts = CallLog.Calls.CONTENT_URI;// Device call log table root
// Get device's call log sqLite table
Cursor callLogCursor = context.getContentResolver().query(
contacts, null, CallLog.Calls.NUMBER + " = ?", new String[]{phoneNumber}
, CallLog.Calls.DATE + " DESC"); // Sorting the results so that the last call be first we get.
int duration1 = callLogCursor.getColumnIndex( CallLog.Calls.DURATION);
if( callLogCursor.moveToFirst() == true ) {
duration = callLogCursor.getString( duration1 ); // Getting the actual duration from your device.
}
callLogCursor.close();
return duration;
how can i find out the last incoming "number" that called to me?(received calls)
please don't answer following cod
it has an error (because the class extends PhoneStateListener and the method needs Activity for extending :
public class CallStat extends PhoneStateListener {
String LOG_TAG = "calllog";
private boolean isPhoneCalling = false;
#Override
public void onCallStateChanged(int state, String incomingNumber) {
if (TelephonyManager.CALL_STATE_RINGING == state) {
// phone ringing
Log.i(LOG_TAG, "RINGING, number: " + incomingNumber);
}
if (TelephonyManager.CALL_STATE_OFFHOOK == state) {
// active
Log.i(LOG_TAG, "OFFHOOK");
isPhoneCalling = true;
}
if (TelephonyManager.CALL_STATE_IDLE == state) {
// run when class initial and phone call ended, need detect flag
// from CALL_STATE_OFFHOOK
Log.i(LOG_TAG, "IDLE number");
if (isPhoneCalling) {
Handler handler = new Handler();
//Put in delay because call log is not updated immediately when state changed
// The dialler takes a little bit of time to write to it 500ms seems to be enough
handler.postDelayed(new Runnable() {
#Override
public void run() {
// get start of cursor
Log.i("CallLogDetailsActivity", "Getting Log activity...");
String[] projection = new String[]{Calls.NUMBER};
Cursor cur = getContentResolver().query(Calls.CONTENT_URI, projection, null, null, Calls.DATE +" desc");
cur.moveToFirst();
String lastCallnumber = cur.getString(0);
}
},500);
isPhoneCalling = false;
}
}
}
}
I know for outgoing but what about incoming?
The code in the previous answer is slightly wrong I believe.
The first argument in the query method should be a URI.
See the following correction:
//fields to select.
String[] strFields = {
android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.TYPE,
android.provider.CallLog.Calls.CACHED_NAME,
android.provider.CallLog.Calls.CACHED_NUMBER_TYPE
};
//only incoming.
String strSelection = android.provider.CallLog.Calls.TYPE + " = " + android.provider.CallLog.Calls.INCOMING_TYPE;
//most recent first
String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
//get a cursor.
Cursor mCallCursor = getContentResolver().query(
android.provider.CallLog.Calls.CONTENT_URI, //content provider URI
strFields, //project (fields to get)
strSelection, //selection
null, //selection args
strOrder //sortorder.
);
mCallCursor.moveToFirst();
String[] strFields = {
android.provider.CallLog.Calls.NUMBER,
android.provider.CallLog.Calls.TYPE,
android.provider.CallLog.Calls.CACHED_NAME,
android.provider.CallLog.Calls.CACHED_NUMBER_TYPE
};
String strOrder = android.provider.CallLog.Calls.DATE + " DESC";
Cursor mCallCursor = getContentResolver().query(
android.provider.CallLog.Calls.INCOMING_TYPE,
strFields,
null,
null,
strOrder
);
mCallCursor.moveToFirst();
This will return the call log of outgoing calls.
Or using your code:
Cursor cur = getContentResolver().query( android.provider.CallLog.Calls.INCOMING_TYPE, projection, null, null, Calls.DATE +" desc");
cur.moveToFirst();
String lastCallnumber = cur.getString(0);
I am developing an application which will store all the incoming and outgoing sms in a text file in SD card.
I am able to listen incoming messages using broadcast receiver. I am finding it very difficult to listen to outgoing SMS.
I know to some extent that a content observer on the sent box or outbox needs to be set, but I don't know how to do it.
How can this be done?
Basically, you have to register a content observer... something like this:
ContentResolver contentResolver = context.getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms/out"),true, yourObserver);
yourObserver is an object (new YourObserver(new Handler())) that could look like this:
class YourObserver extends ContentObserver {
public YourObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// save the message to the SD card here
}
}
So, how exactly do you get the content of the SMS? You must use a Cursor:
// save the message to the SD card here
Uri uriSMSURI = Uri.parse("content://sms/out");
Cursor cur = this.getContentResolver().query(uriSMSURI, null, null, null, null);
// this will make it point to the first record, which is the last SMS sent
cur.moveToNext();
String content = cur.getString(cur.getColumnIndex("body"));
// use cur.getColumnNames() to get a list of all available columns...
// each field that compounds a SMS is represented by a column (phone number, status, etc.)
// then just save all data you want to the SDcard :)
This one is my approach for solving this
Create a service that called from other activity
Create a content observer inside it
#Override
public int onStartCommand(Intent intent, int flag, int startId) {
MyObserver myObserver = new MyObserver(new Handler());
ContentResolver contentResolver = this.getApplicationContext().getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms/sent"), true, myObserver);
return START_STICKY;
}
Create the observer class
class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Uri uriSMSURI = Uri.parse("content://sms/sent");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
cur.moveToNext();
String content = cur.getString(cur.getColumnIndex("body"));
String smsNumber = cur.getString(cur.getColumnIndex("address"));
if (smsNumber == null || smsNumber.length() <= 0) {
smsNumber = "Unknown";
}
cur.close();
if(smsChecker( "OutgoingSMS to " + smsNumber + ": " + content)) {
//save data into database/sd card here
}
}
}
I added a method smsChecker() to check if the new message is just same as the last message
public boolean smsChecker(String sms) {
boolean flagSMS = true;
if (sms.equals(lastSMS)) {
flagSMS = false;
}
else {
lastSMS = sms;
}
//if flagSMS = true, those 2 messages are different
return flagSMS;
}
if i am not mistaken, we use "content://sms/sent" if we ONLY want to check all sent messages, "content://sms/out" if we ONLY want to check all messages inside outbox, and "content://sms" if we want to check ALL messages.
This is my version, which has been verified in Android 6.0+
class smsObserver extends ContentObserver {
private String lastSmsId;
public smsObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Uri uriSMSURI = Uri.parse("content://sms/sent");
Cursor cur = getContentResolver().query(uriSMSURI, null, null, null, null);
cur.moveToNext();
String id = cur.getString(cur.getColumnIndex("_id"));
if (smsChecker(id)) {
String address = cur.getString(cur.getColumnIndex("address"));
// Optional: Check for a specific sender
if (address.equals(phoneNumber)) {
String message = cur.getString(cur.getColumnIndex("body"));
// Use message content for desired functionality
}
}
}
// Prevent duplicate results without overlooking legitimate duplicates
public boolean smsChecker(String smsId) {
boolean flagSMS = true;
if (smsId.equals(lastSmsId)) {
flagSMS = false;
}
else {
lastSmsId = smsId;
}
return flagSMS;
}
}
Place this code where the observer should be enabled
ContentResolver contentResolver = getContentResolver();
contentResolver.registerContentObserver(Uri.parse("content://sms"), true, new smsObserver(new Handler()));
This assumes you are using an activity. Remember that you will need a Context reference to call getContentResolver() from within a service or receiver.
I saw what goes wrong. its on the line:
contentResolver.registerContentObserver(Uri.parse("content://sms/sent"), true, _myObserver);
you must remove '/sent' and just write 'content://sms'
its is already specified in the ContentObserver to look into sent sms.
I'm using registerContentObserver() to be notified as the contacts are changed, but when I register for the content uri:People.CONTENT_URI and when I observe in the log cat I'm getting the notify as "false" even after changing the contact.
I have also overridden the deliverSelfNotification to true. What am I doing wrong?
Not sure what your asking, your question is a bit vague.
Here is how I listen out for changes in the SMS content provider, you may find it useful
String url = "content://sms/";
Uri uri = Uri.parse(url);
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(handler));
/uriSms = Uri.parse("content://sms/inbox");
Cursor c = getContentResolver().query(uriSms, null,null,null,null);
//Log.d("COUNT", "Inbox count : " + c.getCount());
}
class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
#Override public boolean deliverSelfNotifications() {
return false;
}
#Override public void onChange(boolean arg0) {
super.onChange(arg0);
Log.v("SMS", "Notification on SMS observer");
Message msg = new Message();
msg.obj = "xxxxxxxxxx";
handler.sendMessage(msg);
Uri uriSMSURI = Uri.parse("content://sms/");
Cursor cur = getContentResolver().query(uriSMSURI, null, null,
null, null);
cur.moveToNext();
String protocol = cur.getString(cur.getColumnIndex("protocol"));
if(protocol == null){
Log.d("SMS", "SMS SEND");
int threadId = cur.getInt(cur.getColumnIndex("thread_id"));
Log.d("SMS", "SMS SEND ID = " + threadId);
getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadId), null, null);
}
else{
Log.d("SMS", "SMS RECIEVE");
int threadIdIn = cur.getInt(cur.getColumnIndex("thread_id"));
getContentResolver().delete(Uri.parse("content://sms/conversations/" + threadIdIn), null, null);
}
}
If you are targeting anything newer than api level 3,
you should use ContactsContract.Contacts.CONTENT_URI.
and then it's just a matter of: getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contentObserver);
You will not know what has changed with this method though.