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.
Related
I am trying to get all contact from my phone, including get all numbers from contacts with multiple numbers.
So i've build query that while not over run all over contacts, and build Contact user, and have inside query with id selection to get all numbers for each user. but since my inside query is including selection it takes a long time. any other idea?
private Cursor initPhoneCursor() {
try {
// get the contacts URI
final Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// get the name column's name depending on the Android Version
final String nameColumn = Contact.COLUMN_NAME_PHONE;
// declare columns object - init later depending on version
String selection = getQuerySelectionForCursor();
String[] columns = getColumnSelectionForCursor(nameColumn);
if (mApp != null) {
// return cursor from contentresolver
return mApp.getContentResolver().query(phoneUri, columns, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
}
} catch (Exception e) {
// couldn't read phone cursor
CaughtExceptionHandler.reportException(e);
}
return null;
}
private void importContactsFromCursor(Cursor cursor, boolean isSimCard) {
mCurrentContactCursor = initPhoneCursor();
// check cursor is alive
if (cursor != null && !cursor.isClosed()) {
while (cursor.moveToNext() && shouldContinueImport()) {
// // as log as we have contacts, move through them
importContact(cursor, isSimCard);
mCurrentContact++;
}
// when done - close the cursor
cursor.close();
}
}
private void importContact(Cursor cursor, boolean simCard) {
// create Contact object
Contact row = new Contact(cursor, simCard);
// mContactsTimer.onContactCreated();
if (simCard) {
// if simCard, contact must have number
// validate number and create contact
row = validateAndCheckNumber(row, cursor);
}
else {
// if not sim card (phone cursor), a contact might have no numbers,
// single or multiple phone numberss
// let's check if this contact has any numbers
if (hasPhoneNumbers(cursor)) {
// get all of the contact's phone numbers
row = importAllNumbersForContact(row);
}
}
// check if this is valid
final boolean isValidForSaving = row != null && row.hasName() && row.hasNumbers();
if (isValidForSaving && !sStopRequested) {
mContactsToSave.add(row);
}
}
private Contact importAllNumbersForContact(Contact contact) {
// uri of contact phones
Uri contentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// contact_id = ?
String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
String[] selectionArgs = {String.valueOf(contact.getOriginalId())};
// do the query
Cursor phoneCursor = mApp.getContentResolver().query(contentUri, null, selection, selectionArgs, null);
if (phoneCursor != null) {
// save numbers if we got anything
contact = loopThroughContactNumbers(contact, phoneCursor);
// close cursor when done
phoneCursor.close();
}
return contact;
}
Go with the following solution:
Map<String,Contact> contactsMap = new TreeMap<>();
contacts = new ArrayList<>();
Cursor phones = getBaseContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" ASC");
assert phones != null;
while (phones.moveToNext())
{
Contact contact = new Contact();
contact.setDisplayName(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
contact.setPhoneNumber(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
contact.setDisplayPicture(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI)));
contactsMap.put(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)),contact);
}
contacts.addAll(contactsMap.values());
phones.close();
Modify it for all numbers of a contact. You are good to go with.
I need to split getting contacts from phone's contact list database. If user has a lot of contacts loading stucks for few seconds to load what is not very good. I want to divide it with Rx to load 20 contacts a time, but with loading all contacts on start, not with lazy loading. At this moment i tried it with pull of observables with concat, but it collects all the results and return after finishing all of them instead of returning every 20 contacts after getting them and just after returning continue with next pack of contacts. What is wrong with this implementation?
#Override public Observable<List<Contact>> getPhoneContacts() {
return Observable.fromCallable(this::getCursor)
.concatMap(cursor -> {
List<Observable<List<Contact>>> list = new ArrayList<>();
int pagesCount = cursor.getCount()/20 + 1;
for(int i = 0; i < pagesCount; i++){
list.add(Observable.just(getContactList(cursor)));
}
return Observable.concat(list).compose(upstream -> {
cursor.close();
return upstream;
});
});
}
private List<Contact> getContactList(Cursor cursor) {
List<Contact> contacts = new ArrayList<>();
if (cursor != null && !cursor.isClosed() && areContactsPresent(cursor)) {
while (contacts.size() < 20){
if (cursor.moveToNext()) {
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Contact contact = getContact(cursor, id);
if (contact != null) {
contacts.add(contact);
}
}
//else {
// cursor.close();
// break;
//}
}
}
return contacts;
}
private Cursor getCursor(){
return contentResolver.query(ContactsContract.Contacts.CONTENT_URI,
null, ContactsContract.Data.HAS_PHONE_NUMBER+">0", null, ContactsContract.Contacts.DISPLAY_NAME + " ASC");
}
private Contact getContact(Cursor cursor, String id) {
Contact contact = null;
Cursor phonesCursor = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{id}, null);
if (phonesCursor != null) {
while (phonesCursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(
ContactsContract.Contacts.DISPLAY_NAME));
String phoneNo = phonesCursor.getString(
phonesCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (!phoneNo.isEmpty()) {
contact = Contact.create(name, phoneNo);
}
}
phonesCursor.close();
}
return contact;
}
You source observable needs to look something like that
Observable.create((ObservableOnSubscribe<List<Contact>>) emitter -> {
int pagesCount = cursor.getCount()/20 + 1;
for(int i = 0; i < pagesCount; i++){
emitter.onNext(getContactList(cursor)); // Passes list with 20 items to onNext()
}
emitter.onComplete();
});
Your data source now returns List<Contact> instead of a single Contact, which means each emission will provide you with a list of contacts, each list has 20 items as per your implementation.
Then you can update UI with each emission, instead of waiting for all of the contacts to load.
When I click on fab to write a new SMS in my application, it is opening too slowly. When I comment readcontactData or adapter it is working Quickly. where is the problem
adapter =new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,new ArrayList<String>());
readContactData();
contactNumber.setThreshold(1);
//Set adapter to AutoCompleteTextView
contactNumber.setAdapter(adapter);
contactNumber.setOnItemClickListener(this);
private void readContactData() {
try {
ContentResolver contentResolver = getBaseContext().getContentResolver();
// Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
//Query to get contact name
Cursor cursor =contentResolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
// If data found in contacts
if (cursor.getCount() > 0) {
Log.i("AutocompleteContacts", "Reading contacts........");
int k=0;
while (cursor.moveToNext())
{
String name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String id = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
String hasPhone=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
//Check contact have phone number
if ((Integer.parseInt(hasPhone) > 0))
{
//Create query to get phone number by contact id
Cursor pCur = contentResolver
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + id,
null,
null);
int j=0;
while (pCur.moveToNext())
{
// Sometimes get multiple data
if(j==0)
{
// Get Phone number
String phoneNumber =pCur.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// Add contacts names to adapter
adapter.add(name);
//adapter.add(phoneNumber);
// Add ArrayList names to adapter
phoneValueArr.add(phoneNumber.toString());
nameValueArr.add(name.toString());
j++;
//k++;
}
} // End while loop
pCur.close();
} // End if
} // End while loop
//} // End Cursor value check
cursor.close();
}
catch (Exception e)
{
e.printStackTrace();
Log.d("this is an error","akdjfkandkfj");
}
}**
You are loading data in Main thread. So its slow. Use Async Task for readContact.
Writing too much code in onCreate, slow the loading.
I am developing an application in which I list the device contacts, and perform some manipulation with them. I listen to contact changes as described in the following links: Link 1, Link 2
My code is as follows:
public class ContactService extends Service {
private int mContactCount;
Cursor cursor = null;
private int contactStateCheckingFlag=0;
static ContentResolver mContentResolver = null;
public static final String AUTHORITY = "com.example.contacts";
public static final String ACCOUNT_TYPE = "com.example.myapplication.account";
public static final String ACCOUNT = "myapplication";
Account mAccount;
Bundle settingsBundle;
int i=0;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();// Get contact count at start of service
mContactCount = getContactCount();
this.getContentResolver().registerContentObserver(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, true, mObserver);
Cursor curval = getApplicationContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, null, null, null);
if (curval != null && curval.getCount() > 0) {
curval.getCount();
}
curval.close();
}
private int getContactCount() {
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null,null);
if (cursor != null) {
return cursor.getCount();
} else {
cursor.close();
return 0;
}
} catch (Exception ignore) {
} finally {
cursor.close();
}
return 0;
}
private ContentObserver mObserver = new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
new ContactServiceAsyncClass().execute();
}
};
private class ContactServiceAsyncClass extends AsyncTask<Void, Void, Void> {
ArrayList<Integer> arrayListContactID = new ArrayList<Integer>();
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... arg0) {
// Get the current count of contacts
int currentCount = getContactCount();
// Add New Contact
if (currentCount > mContactCount){
Cursor contactCursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (contactCursor.getCount()<=0) {
Log.d("Contact Cursor count"," is zero");
}else {
Log.d("Contact Cursor count", " > 0");
// Fetch all contact ID from cursor
if(contactCursor.moveToFirst()){
do {
int contactID = contactCursor.getInt(contactCursor.getColumnIndex(ContactsContract.Data._ID));
arrayListContactID.add(contactID);
} while (contactCursor.moveToNext());
}
// Sort the array list having all contact ID
Collections.sort(arrayListContactID);
Integer maxID=Collections.max(arrayListContactID);
Log.d("maxID", ""+maxID);
// Get details of new added contact from contact id
String whereName = ContactsContract.Data._ID + " = ?";// Where condition
String[] whereNameParams = new String[] { ""+maxID}; // Pass maxID
Cursor cursorNewContact = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, whereName, whereNameParams, null);
if(cursorNewContact.getCount()<=0){
}else {
if(cursorNewContact.moveToFirst()){
do{
// Fetch new added contact details
} while(cursorNewContact.moveToNext());
}
}
cursorNewContact.close();
}
contactCursor.close();
} else if(currentCount < mContactCount){
// Delete Contact/
// CONTACT DELETED.
} else if(currentCount == mContactCount){
// Update Contact1
}
mContactCount = currentCount;
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
I am able to fetch new added contact. The question is how to delete and update contact? How to know which contact is deleted and updated, as the contact change broadcast doesn't specify the id of the contact that changed?
Please provide your valuable suggestions and guide me in detail.
Thank you.
For delete operation,
1.First you store the previous list of contacts id in local database.
for example: you added contact id`s are 123,124,125.
Now we assume your last added contact(125) was deleted.
How we find it?.
simple first get the list of old contact list. and compare with current contact list.
If old contact list element not in the new list, that contact is deleted from phone.
Note: If delete operation complete, you need to update the contact id`s into DB.
For Update operation,
1.Use VERSION flag for indicating any changes in your contact.
2.VERSION default value is 1. if you modify the contacts,it automatically increase to 2.
3.So you need to store old version value in your local DB. and compare the version value increase or not. If increase the VERSION value you need to update this contact.
Refer the official link,
https://developer.android.com/reference/android/provider/ContactsContract.RawContacts.html
For complete project,
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.0.4_r2.1/com/android/exchange/adapter/ContactsSyncAdapter.java?av=f
I am trying to store the user contacts on Parse.com dashboard. I run my project again & again to store contacts.
But everytime I see different number of contacts stored, some of the contacts(data ie friend & phone no) have been lost.
I am using all this code:
public class MainActivity extends Activity {
ParseObject testObject;
EditText et;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Parse.initialize(this, "2dSVesLx7lUKxhSb7B4bSmAOlIVAWONM8sIQTtZb", "CkikNpzXV2eR0QugHnZCQoQjbh6IDgHrESG0KIBS");
et = (EditText)findViewById(R.id.editText1);
et.setOnEditorActionListener(new OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
boolean handled = false;
if (actionId == EditorInfo.IME_ACTION_DONE) {
// TODO do something
handled = true;
testObject = new ParseObject("India"+et.getText().toString());
readDistinctContacts("India"+et.getText().toString());
// readContacts();
}
return handled;
}
});
}
public void readDistinctContacts(String s) {
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(s);
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();
}
}
}
cur.close();
}
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("India"+et.getText().toString());
testObject.put("names", name);
// testObject.saveInBackground();
// 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();
}
}
}
}
}
I have used both the methods like in code readcontacts(), readDistinctContacts() , but both are giving me the same problem. Look at the snapshot of my dashboard, it shows different number of contacts every time
Any solution to manage this problem?
Thanks in advance
UPDATE
Thanks to askoka, Using saveEventually() there was no data loss but it takes 3-4 minutes to store 400 parseobjects(ie. contacts) by 400 push request!. I want the storage should be fast and efficient, can anyone please tell me the best way to make it happen?
your saveInBackgroundmight be experiencing problems, try passing in a callback to see if there is an error.
saveInBackground(new SaveCallback() {
public void done(ParseException e) {
if (e != null) Log.e("ParseAPITest", "saveInBackground failed: " + e.toString());
}
});
and implement retry logic on your own or you can try :
replacing saveInBackground with saveEventually, which will retry if there is an error in message push.
batch your push messages by saving all the ParseObjects in a List and use saveAllInBackground preferably with callback, this will try to batch your push requests as discussed in saveAll
if your app use-case allows, you can create just one ParseObject and add all contacts to this single ParseObject and call saveEventually - this should only take one push request message to parse server, so the delay will be reduced.
In your readDistinctContacts function you already have contacts ArrayList, in which you save each contact as a ParseObject. You just need to save that list into one root ParseObject and call saveEventually() on it - this would result in just one request to the parse server.
Just before the while loop add ParseObject root = new ParseObject(s); and inside the while loop replace ParseObject testObject = new ParseObject(s); with ParseObject testObject = new ParseObject("Contact" + counter);. Get rid of testObject.saveInBackground();.
Finally add root.addAll(root.getClassName(), contacts);root.saveEventually(); after while loop. This should save all your contacts in one go (request), and saveEventually will handle any retries needed.