Android - ContentObserver not getting called - android

I'm trying to extract the Contacts when the contact table is changed. It was working fine but now doesn't work. It only works a few times. I'm using ContentObserver to get the event.
Here's the code to register the ContentObserver. I'm registering it on a Service to be constantly listening.
public void onCreate() {
super.onCreate();
context = this;
db = new Database(context);
Log.i("**********", "Started Service!");
Contacts contacts = new Contacts(context);
context.getContentResolver().registerContentObserver (ContactsContract.CommonDataKinds.Phone.CONTENT_URI, true, contacts);
}
And here's the code when I extract the contacts name and this stuf:
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.i("********","*****");
db = new Database(co);
db.open();
if (db.Preferences(3) && new CheckConexion().isOnline(co)) {
Cursor phones = co.getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null, null);
while (phones.moveToNext()) {
try {
name = phones
.getString(phones
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
phoneNumber = phones
.getString(phones
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
JSONObject jobject = db.select_contact(name, phoneNumber);
String type1 = jobject.getString("type");
if (type1.equals("upload")) {
if (!(name.equals("") && phoneNumber.equals(""))) {
JSONObject jobject2 = new JSONObject();
jobject2.put("name", name);
jobject2.put("phone", phoneNumber);
String value_json = String.valueOf(jobject2);
upload(value_json, co);
Log.i("********", "Upload on the db" + name + " "
+ phoneNumber);
}
} else {
return;
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
db.close();
} else {
db.close();
}
}

Oncreate() is called only once for a service when it is started for the first time. If you are starting the service again and again then onStartCommand() will be called directly. Therefore I feel its the observer registration is not being retained and is getting lost.

Related

Is there any other way of accessing to contacts without using `getContentResolver()`?

My app is always slow and sometimes crashes because to access to contacts list, I am using getContentResolver() which is making my app to run another additional process to main process. Whenever that additional process is running, my app starts to slow down and crashing.
So, is there any idea of accessing to contacts list without passing to that getContentResolver()?
Use AsyncTaskLoader for fetching contact from device, it is recommended because it is asynchronous and also works well with activity lifecycle.
You should use an AsynTask to do this work in background thread
private class LoadContacts extends AsyncTask<Void, Boolean, Boolean> {
protected void onPreExecute() {
Log.e("LS", "Start !");
}
#Override
protected Boolean doInBackground(Void... params) {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
try {
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (cur.getInt(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)) > 0) {
Cursor pCur = cr.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id},
null
);
while (pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String data = "Name : " + name + " - Phone : " + phoneNo;
}
pCur.close();
}
}
}
cur.close();
} catch (NullPointerException | java.io.IOException e) {
Log.e("LS", e.getMessage());
}
return true;
}
protected void onPostExecute(Boolean result) {
Log.e("LS", "Done !");
}
}

How to get last inserted contact number from the phone book android?

How can i fetch the last inserted contact number from the android phone book. I already done with the fetching all the unique contact numbers and its count from the database and i have also made a ContentObserver for listening the updates related to phone book.but now i want last inserted contact number. I am putting my whole code over here.
This is my code to fetch all the contacts :-
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
listNumbers.add(phoneNumber);
}
ArrayList<String> unique = removeDuplicates(listNumbers);
for (String element : unique) {
System.out.println(element);
}
sb = new StringBuffer();
for (String item : unique) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(item);
}
numbersString = sb.toString();
// Log.e("BUFFER", numbersString.toString());
phones.close();
Log.e("SIZE", unique.size() + "");
And Now this is the code for contentobserver :-
private ContentObserver mObserver = new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
final int currentCount = getContactCount();
if (currentCount < mContactCount) {
// DELETE HAPPEN.
Log.e("STATUS===>", "Deletion");
} else if (currentCount == mContactCount) {
// UPDATE HAPPEN.
} else {
// INSERT HAPPEN.
Log.e("STATUS===>", "Insertion");
}
mContactCount = currentCount;
}
};
In onchange INSERT Condition i want that newly added contact number.

What is the best way to get distinct contacts in Android

I am successfully storing contacts in parse.com dashboard data browser by this code.
public void readContacts(){
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) ==1) {
System.out.println(name );
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(
pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println( phone);
testObject.put("phonenumber", phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
But there is no check for the duplicate contacts !
It stores all the contacts duplicate from sim / phone memory.
How can it be avoided ?
One possible method I think is to store distinct names(contact) in local database, & then retrieving that data to store it in parse.com
Is there exists a better way ?
Thanks in advance...
An easy approach could be to load the data to a MatrixCursor with no duplicate data. For example lets assume you have a cursor c1 will many contacts, but you need a cursor with no duplicate data. Here is what you could do:
MatrixCursor mc = new MatrixCursor(new String[] {
Phone._ID,
Phone.DISPLAY_NAME_PRIMARY,
Phone.NUMBER
});
String lastNumber = "";
while(c1.moveToNext()){
String id = c1.getString(c1.getColumnIndexOrThrow(Phone._ID));
String name = c1.getString(c1.getColumnIndexOrThrow(Phone.DISPLAY_NAME_PRIMARY)));
String number = c1.getString(c1.getColumnIndexOrThrow(Phone.NUMBER));
//Some condition to check previous data is not matched and only then add row
if(!lastNumber.contains(number)){
lastNumber = number;
mc.addRow(new String[]{id, name, number});
}
}
c1.close();
Make an instance of MatrixCursor with same columns, and then load if last number or contact name does not match that of the previous contact. The condition for checking is upto you. Query data in some order so that the duplicate contacts stay together first.
Once the MatrixCursor is loaded you can fetch data from it. You could also attach it to a view through a custom CursorLoader or CursorAdapter.
Please see the below method. You will get contacts list which does not have duplicate phone numbers.
public void readContacts() {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
ArrayList<ParseObject> contacts = new ArrayList<ParseObject>();
ArrayList<String> list = new ArrayList<String>();
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) == 1) {
System.out.println(name);
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println(phone);
testObject.put("phonenumber", phone);
if(!list.contains(phone)) {
contacts.add(testObject);
}
list.add(phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
Set is a collection in java that does not allow duplicates. You can put your data into a set with number as a key and name as value, to avoid duplicate numbers.
And later you can take them back from set and put into your testObject with name as key and number as value.
Here is the Solution that i worked out for you....
You can go through the logcat for information about how it works 100%
import java.util.ArrayList;
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
public class MainActivity extends Activity {
String ClsSimPhonename = null;
String ClsSimphoneNo = null;
public static ArrayList<String> phonecontact = new ArrayList<String>();
public static ArrayList<String> simcontact = new ArrayList<String>();
public static ArrayList<String> totalcontact = new ArrayList<String>();
public static ArrayList<String> repeatedcontact = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get phone contact...
getphonecontact();
// get sim contact...
getsimcard_contact();
System.out.println("phone??? " + phonecontact);
System.out.println("sim??? " + simcontact);
System.out.println("sim_size??? " + simcontact.size());
System.out.println("phone_size??? " + phonecontact.size());
System.out.println("totalcontact_size??? " + totalcontact.size());
// filter process beigins here....
nowFilterContact();
}
private void nowFilterContact() {
// TODO Auto-generated method stub
// determine which contact have more item....
if (simcontact.size() > phonecontact.size()) {
onemorefiltermethod(simcontact.size(), simcontact, phonecontact);
} else {
onemorefiltermethod(phonecontact.size(), phonecontact, simcontact);
}
}
private void onemorefiltermethod(int size, ArrayList<String> contacts,
ArrayList<String> contact2) {
// TODO Auto-generated method stub
// compare both contact and get repeated contacts....
for (int i = 0; i < size; i++) {
try {
if (contacts.contains(contact2.get(i))) {
// add repeated contacts to array....
repeatedcontact.add(contact2.get(i));
}
} catch (Exception e) {
}
}
System.out.println("repeatedcontact_size??? " + repeatedcontact.size());
// now delete repeated contact from total contact
now_deletedrepeated_contact_from_total();
}
private void now_deletedrepeated_contact_from_total() {
// TODO Auto-generated method stub
for (int i = 0; i < totalcontact.size(); i++) {
try {
if (totalcontact.contains(repeatedcontact.get(i))) {
totalcontact.remove(repeatedcontact.get(i));
}
} catch (Exception e) {
}
}
System.out.println("Final contact size" + totalcontact.size());
System.out.println("Final contact " + totalcontact);
}
private void getsimcard_contact() {
// TODO Auto-generated method stub
try {
Uri simUri = Uri.parse("content://icc/adn");
Cursor cursorSim = this.getContentResolver().query(simUri, null,
null, null, null);
while (cursorSim.moveToNext()) {
ClsSimPhonename = cursorSim.getString(cursorSim
.getColumnIndex("name"));
ClsSimphoneNo = cursorSim.getString(cursorSim
.getColumnIndex("number"));
ClsSimphoneNo.replaceAll("\\D", "");
ClsSimphoneNo.replaceAll("&", "");
ClsSimPhonename = ClsSimPhonename.replace("|", "");
/*
* add contact from phone to array phone array and total array
*/
phonecontact.add(ClsSimphoneNo);
totalcontact.add(ClsSimphoneNo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getphonecontact() {
// TODO Auto-generated method stub
try {
String[] PROJECTION = new String[] { Contacts._ID,
Contacts.DISPLAY_NAME, Phone.NUMBER };
Cursor c = managedQuery(Phone.CONTENT_URI, PROJECTION, null, null,
null);
if (c.moveToFirst()) {
String ClsPhonename = null;
String ClsphoneNo = null;
do {
ClsPhonename = c.getString(c
.getColumnIndex(Contacts.DISPLAY_NAME));
ClsphoneNo = c.getString(c.getColumnIndex(Phone.NUMBER));
/*
* add contact from sim to array sim array and total array
*/
simcontact.add(ClsphoneNo);
totalcontact.add(ClsphoneNo);
ClsphoneNo.replaceAll("\\D", "");
ClsPhonename = ClsPhonename.replaceAll("&", "");
ClsPhonename.replace("|", "");
String ClsPhoneName = ClsPhonename.replace("|", "");
} while (c.moveToNext());
}
} catch (Exception e) {
}
}
}
Permission
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Your output is on now_deletedrepeated_contact_from_total() method.
Check totalcontact array value for Final output

How to list all Call logs from Log list including Sms and email logs also?

I want to access the sms logs also . but I don't find any way , I already accessed the call logs using CallLog.Calls ,it's unable to list sms logs .
below code is listing only call logs , but not all logs even sms logs are not listed (sms logs means logs created because received and sent sms) . please help me to find the way to retrieve the sms logs . please ans if possible sir .
Cursor cursor = managedQuery(CallLog.Calls.CONTENT_URI, null, null,
null, Calls.DATE + " DESC");
// cursor is inited
cursor.moveToFirst();
String name;
String number;
int type;
do {
name = "";
number = "";
type = -1;
try {
number = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.NUMBER));
type = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
try {
name = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.CACHED_NAME));
} catch (Exception e) {
} finally {
if (name == null || name.equals("")) {
name = "UNKNOWN";
}
}
Log.e("My App", name + " : "+number + " : "+type);
} catch (Exception e) {
Log.e("My App", "Error in creation");
}
} while (cursor.moveToNext());
this is just suggestion. you get better answer rather then this...
see if you want to get sms log then use below code.. and you already get call log.. so if you want to mix call and sms log in one list then you must have to do that by date..
in call log you get date & time
in sms also you get date & time
sms log code...
put this in method and use your own way..
CharSequence contentTitle = getString(R.string.app_name);
final ProgressDialog progDailog = ProgressDialog.show(
All_logs_tab.this, contentTitle, "Please wait...", true);
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
/* finish sms load */
}
};
new Thread() {
public void run() {
try {
Uri myMessage = Uri.parse("content://sms/");
ContentResolver cr = con.getContentResolver();
Cursor c = cr.query(myMessage, new String[] { "_id",
"address", "date", "body", "read" }, null,
null, null);
startManagingCursor(c);
getSmsLogs(c, con);
} catch (Exception e) {
}
handler.sendEmptyMessage(0);
progDailog.dismiss();
}
}.start();
.................................................
i added all sms details in array list
ArrayList<String> sms_id = new ArrayList<String>();
ArrayList<String> sms_num = new ArrayList<String>();
ArrayList<String> sms_Name = new ArrayList<String>();
ArrayList<String> sms_dt = new ArrayList<String>();
ArrayList<String> sms_body = new ArrayList<String>();
........................................................
public void getSmsLogs(Cursor c, Context con) {
if (sms_num.size() > 0) {
sms_id.clear();
sms_num.clear();
sms_Name.clear();
sms_body.clear();
sms_dt.clear();
}
try {
if (c.moveToFirst()) {
do {
if (c.getString(c.getColumnIndexOrThrow("address")) == null) {
c.moveToNext();
continue;
}
String _id = c.getString(c.getColumnIndexOrThrow("_id"))
.toString();
String Number = c.getString(
c.getColumnIndexOrThrow("address")).toString();
String dat = c.getString(c.getColumnIndexOrThrow("date"))
.toString();
String as = (String) get_dt(dat, "dd/MM/yyyy, hh.mma");
String Body = c.getString(c.getColumnIndexOrThrow("body"))
.toString();
String name = getContactDisplayNameByNumber("" + Number,
con);
if (name.length() <= 0 || name.length() == 1) {
name = "no name";
}
sms_id.add(_id);
sms_num.add(Number);
sms_Name.add("" + name);
sms_body.add(Body);
sms_dt.add(as);
} while (c.moveToNext());
}
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
You need the URI to the SMS messages's table this will retrieve you the data. It can be found in the base source code, however; it is not recommended by Google to do this.
use this link Android call logs to retrieve call logs. for sms do the same by using SMS_URI="content://sms" , but it is not recommended as it is not public URi.

Delete call from call log after call end

I am new to Android development. I want to make a call to a number but I don't want to store the number in my Call log. How can I delete the number from call log after the call ends?
First you have to set up a broadcast receiver to detect the phone state. Here's the exact same question: Stackoverflow - Intent to be fired when a call ends?
And now for deleting the call log entry, here is the first link on google: Call log deletion in Android
In the example he deletes all call entry for a specific number, but you can change the query to delete the entry for a specific call log id.
Hope this helps.
Cheers
Im using 4.2.2 anyway i had to modify the aftab's code as it was not working for me. It could be a asych issue giving what i was trying to do is update the call log right after an incoming call is ended. I think i have to give O/S enough time to update the table before i delete the entry or it wont exist :
private void deleteNumber(String phoneNumber) {
try {
Thread.sleep(4000);
String strNumberOne[] = { phoneNumber };
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI, null,
CallLog.Calls.NUMBER + " = ? ", strNumberOne, "");
boolean bol = cursor.moveToFirst();
if (bol) {
do {
int idOfRowToDelete = cursor.getInt(cursor
.getColumnIndex(CallLog.Calls._ID));
context.getContentResolver().delete(
CallLog.Calls.CONTENT_URI,
CallLog.Calls._ID + "= ? ",
new String[] { String.valueOf(idOfRowToDelete) });
} while (cursor.moveToNext());
}
} catch (Exception ex) {
Log.v("deleteNumber",
"Exception, unable to remove # from call log: "
+ ex.toString());
}
}
and to call the function i run on another thread (since im sleeping) :
new Thread() {
public void run() {
deleteNumber(incomingNumber);
}
}.start();
after adding the sleep it seems to work when trying to delete right after a call is ended.
UPDATE: after last comment realized we can set up a contentobserver on the android provider call log uri:
public class BlockerContentObserver extends ContentObserver{
private Context context;
private String phoneNumber;
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public BlockerContentObserver(Handler handler,Context context) {
super(handler);
this.context=context;
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange) {
// TODO Auto-generated method stub
super.onChange(selfChange);
Log.v(Consts.TAG,"has call log changed:"+selfChange);
deleteNumber(phoneNumber);
}
private void deleteNumber(String phoneNumber) {
try {
String strNumberOne[] = { phoneNumber };
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI, null,
CallLog.Calls.NUMBER + " = ? ", strNumberOne, "");
boolean bol = cursor.moveToFirst();
if (bol) {
do {
int idOfRowToDelete = cursor.getInt(cursor
.getColumnIndex(CallLog.Calls._ID));
context.getContentResolver().delete(
CallLog.Calls.CONTENT_URI,
CallLog.Calls._ID + "= ? ",
new String[] { String.valueOf(idOfRowToDelete) });
} while (cursor.moveToNext());
}
} catch (Exception ex) {
Log.v(Consts.TAG,
"Exception, unable to remove # from call log: "
+ ex.toString());
}
}
}
Now we register to listen to changes in the call log DB using this:
mContentObserver = new BlockerContentObserver(new Handler(), context);
then we make a method to either register for events or unreigster:
/*handles the registration of our content observer used for monitoring the call log*/
private void RegisterContentObserver(boolean shouldRegister){
if(shouldRegister)
{
context.getContentResolver().registerContentObserver(
android.provider.CallLog.Calls.CONTENT_URI,
true,
mContentObserver);
}
else {
try {
context.getContentResolver().unregisterContentObserver(mContentObserver);
} catch (IllegalStateException ise) {
// Do Nothing. Observer has already been unregistered.
}
}
}
I just try this method its working great on my HTC with 4.0.3
private void deleteNumber() {
try {
String strNumberOne[] = { "00577698160" };
Cursor cursor = getContentResolver().query(CallLog.Calls.CONTENT_URI, null, CallLog.Calls.NUMBER + " = ? ", strNumberOne, "");
boolean bol = cursor.moveToFirst();
if (bol) {
do {
int idOfRowToDelete = cursor.getInt(cursor.getColumnIndex(CallLog.Calls._ID));
getContentResolver().delete(Uri.withAppendedPath(CallLog.Calls.CONTENT_URI, String.valueOf(idOfRowToDelete)), "", null);
} while (cursor.moveToNext());
}
} catch (Exception ex) {
System.out.print("Exception here ");
}
}
modified version of earlier answsers. you don't really need a while loop. Also you don't need Thread.sleep(4000), register a ContentObserver for CallLog.Calls.CONTENT_URI and call the following method in onChange. but just before calling that make sure you unregister that ContentObserver
public static void deleteLastCallLog(Context context, String phoneNumber) {
try {
//Thread.sleep(4000);
String strNumberOne[] = { phoneNumber };
Cursor cursor = context.getContentResolver().query(
CallLog.Calls.CONTENT_URI, null,
CallLog.Calls.NUMBER + " = ? ", strNumberOne, CallLog.Calls.DATE + " DESC");
if (cursor.moveToFirst()) {
int idOfRowToDelete = cursor.getInt(cursor.getColumnIndex(CallLog.Calls._ID));
int foo = context.getContentResolver().delete(
CallLog.Calls.CONTENT_URI,
CallLog.Calls._ID + " = ? ",
new String[] { String.valueOf(idOfRowToDelete) });
}
} catch (Exception ex) {
Log.v("deleteNumber",
"Exception, unable to remove # from call log: "
+ ex.toString());
}
}

Categories

Resources