I'm trying to make my app update some contacts but it's updating the wrong people. I get the contact Name, Number and Raw Id. Then if it is true to my if I change his number and update it by his Raw ID. That's my code:
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
{
String numero;
String fnum;
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
int id = phones.getInt(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.RAW_CONTACT_ID));
String tipo = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
phoneNumber = phoneNumber.replace(" ", "");
phoneNumber = phoneNumber.replace("-", "");
phoneNumber = phoneNumber.replace("+", "");
phoneNumber = phoneNumber.replace("*", "");
phoneNumber = phoneNumber.replace("#", "");
int tamanho = phoneNumber.length();
numero = phoneNumber;
if (tamanho == 12) {
if (checar.indexOf(numero.substring(1, 3) + ",") != -1) {
if(numero.substring(3).startsWith("9")){
fnum = numero.substring(0, 3) + "" + numero.substring(4);
update(id, fnum, tipo);
}
}
}
Thread.sleep(2000);
}
phones.close();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
And that's the update method:
public void update(int id, String number, String tipo)
{
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
// Number
builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI);
builder.withSelection(ContactsContract.Data.CONTACT_ID + "=?" + " AND " + ContactsContract.Data.MIMETYPE + "=?"+ " AND " + ContactsContract.CommonDataKinds.Organization.TYPE + "=?", new String[]{String.valueOf(id), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE, tipo});
builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number);
ops.add(builder.build());
// Update
try
{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
}
catch (Exception e)
{
e.printStackTrace();
}
}
What am I doing wrong?
I think that what's wrong is that you're retrieving RAW_CONTACT_ID when you get the number, but in update() you're passing this value to the column CONTACT_ID. The first one points to raw contacts, but the second one points to the Contacts table. Don't mix them!
I also notice that you're trying to update the ORGANIZATION column with the value of Phone.TYPE, which may or may not work.
Related
I want to fetch 50 by 50 contacts from the contact list.
I tried for loop but it gives me 10 contacts randomly.
How to fetch 50 by 50 contacts .. please help me
My code :
ArrayList<Contact_Model> contactList = new ArrayList<Contact_Model>();
Uri uri = ContactsContract.Contacts.CONTENT_URI;
Cursor contactsCursor = getContentResolver().query(uri, null, null,
null, ContactsContract.Contacts.DISPLAY_NAME + " ASC "); // Return
if (contactsCursor.moveToFirst()) {
do {
long contctId = contactsCursor.getLong(contactsCursor.getColumnIndex("_ID"));
Uri dataUri = ContactsContract.Data.CONTENT_URI; // URI to get
Cursor dataCursor = getContentResolver().query(dataUri, null,
ContactsContract.Data.CONTACT_ID + " = " + contctId,
null, null);
// Strings to get all details
String displayName = "";
String mobilePhone = "";
String contactNumbers = "";
String cNumber = "";
String contactImage = "";
String imnage = "";
Cursor phonesCursor = null;
Person.Urls urls;
try {
Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode("Phone number"));
phonesCursor = context.getContentResolver().query(phoneUri, new String[]{ContactsContract.PhoneLookup.PHOTO_THUMBNAIL_URI}, null, null, null);
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
if (dataCursor.moveToFirst()) {
try {
imnage = dataCursor.getString(1);
Log.e("detail", "==============" + imnage);
} catch (NullPointerException e) {
e.printStackTrace();
}
}
if (dataCursor.moveToFirst()) {
displayName = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));// get
do {
for (i = 0; i < 50; i++) {
if (dataCursor. getString(dataCursor.getColumnIndex("mimetype")).equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
switch (dataCursor.getInt(dataCursor.getColumnIndex("data2"))) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
contactNumbers = dataCursor.getString(dataCursor.getColumnIndex("data1"));
contactNumbers += mobilePhone;
int id = 1;
if (String.valueOf(contactNumbers).charAt(0) == '+') {
if (contactNumbers.length() == 13) {
String trim_num = contactNumbers.substring(3);
cNumber = trim_num;
cNumber = cNumber.replaceAll(" ", "");
Log.d("number", cNumber);
}
} else {
cNumber = contactNumbers;
cNumber = cNumber.replaceAll(" ", "");
Log.d("without + number", cNumber);
}
// break;
}
}
}
break;
} while (dataCursor.moveToNext()); // Now move to next
if (!cNumber.equals("")) {
contact = new Contact();
contact.setContctId(String.valueOf(contctId));
contact.setContactNumber(cNumber);
contact.setContactName(displayName);
contact.setContactImg(imnage);
contact.save();
contactList.add(new Contact_Model(displayName, cNumber, imnage));// Finally add
} else {
Log.d("Contact : ", "Don't add empty contact");
}
}
} while (contactsCursor.moveToNext());
}
I also tried LIMIT 50 in cursor.
but when i use LIMIT no contacts available
Cursor contactsCursor = getContentResolver().query(uri,
null, null, null, "LIMIT 10, " + count);
count += 10;
Way 1
If you want pagination in query then use offset
final Cursor c = getContentResolver.query(uri,null,null,null," LIMIT 50 OFFSET 2");
Hold value of last offset and send ++offset the next time.
Way 2
You can get all contacts at once, and then set in list by using pagination.
#Related question.
Suggestion
I faced this problem also, when contacts are too much eg. 500-1000, then it takes some seconds to fetch.
I solved it by fetching contact list before that activity appear. I fetched contacts and hold them in Application class, and cleared after use (to remove memory leak).
i have a problem in update existing contact in Android. My code execute about 400 contact but it take me about 20s to update it. Here is my code.
public class Contact {
private long contactId;
private String phoneNumber;
private int phoneType;
}
Then i try to update each contact filter by ID and Type:
ArrayList list = arrayLists[0];
for (int i = 0; i < list.size(); i++) {
Contact contact = list.get(i);
long contactID = contact.getContactId();
String newPhoneNumber = contact.getPhoneNumber();
int phoneType = contact.getPhoneType();
updateContact(contactID, newPhoneNumber, phoneType);
}
Here is my updateContact funtion:
private void updateContact(long contactID, String newPhoneNumber, int phoneType) {
ContentResolver cr = getContentResolver();
String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? AND " + ContactsContract.CommonDataKinds.Phone.TYPE + " = ?";
String[] whereParams = new String[]{contactID + "", phoneType + ""};
ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber);
Uri dataUri = ContactsContract.Data.CONTENT_URI;
cr.update(dataUri, contentValues, where, whereParams);
}
I tried other method to update contact but it also take same time ( about 20s for 400 contact)
private void updateContact(long contactID, String newPhoneNumber, int phoneType) {
ContentResolver cr = getContentResolver();
String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ? AND " +
ContactsContract.CommonDataKinds.Phone.TYPE + " = ?";
String[] params = new String[]{contactID + "", phoneType + ""};
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(where, params)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber)
.build());
try {
cr.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
}
What should i do, how can i improve the performance of update job. I expert it can update 400 contact in 3-5s
I'm trying to use this code to allow a user edit a contact's name and number. I get no errors and when I print nameofcontact and numberofcontact in my log it shows me the latest changes I've made to the name and number of the contact.
But it's not saving to my contacts database. Any ideas what's wrong?
public void editButton(View view) {
// the text in the 'nameofcontact' edittext box, can be modified by the user
contactname = nameofcontact.getText().toString();
// the text in the 'numberofcontact' edittext box, can be modified by the user
contactnumber = numberofcontact.getText().toString();
ContentResolver cr = getContentResolver();
String where = ContactsContract.Data.DISPLAY_NAME + " = ? AND " +
ContactsContract.Data.MIMETYPE + " = ? AND " +
String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE) + " = ? ";
String[] params = new String[] {contactname,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE_HOME)};
Cursor phoneCur = getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, where, params, null);
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
// if ( (null == phoneCur) ) {
// createContact(name, phone);
// } else
{
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(where, params)
.withValue(ContactsContract.CommonDataKinds.Phone.DATA, contactnumber)
.build());
}
phoneCur.close();
try {
cr.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println (contactname);
System.out.println (contactnumber);
Toast.makeText(this, "Updated", Toast.LENGTH_SHORT).show();
}
Please check you add below permission in your manifeast or not
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
and you can use this method it works for me.
public boolean updateContact(String name, String number, String ContactId) {
boolean success = true;
String phnumexp = "^[0-9]*$";
try {
name = name.trim();
number = number.trim();
if (name.equals("") && number.equals("")) {
success = false;
} else if ((!number.equals("")) && (!match(number, phnumexp))) {
success = false;
} else {
ContentResolver contentResolver = SwipableHomeActivity.this
.getContentResolver();
String where = Data.CONTACT_ID + " = ? AND "
+ Data.MIMETYPE + " = ?";
String[] nameParams = new String[]{
ContactId,
StructuredName.CONTENT_ITEM_TYPE};
String[] numberParams = new String[]{
ContactId,
Phone.CONTENT_ITEM_TYPE};
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
if (!name.equals("")) {
ops.add(ContentProviderOperation
.newUpdate(
Data.CONTENT_URI)
.withSelection(where, nameParams)
.withValue(StructuredName.DISPLAY_NAME, name)
.build());
}
if (!number.equals("")) {
ops.add(ContentProviderOperation
.newUpdate(
Data.CONTENT_URI)
.withSelection(where, numberParams)
.withValue(Phone.NUMBER, number).build());
}
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
}
} catch (Exception e) {
e.printStackTrace();
success = false;
}
return success;
}
When a one of the contact have multiple numbers, for example:
Display name: GuessWho TYPE = home Number = homeNumber
TYPE = mobile Number = mobileNumber TYPE = other
Number = otherNumber ...
in conclusion ... one from those.
How I can remove a TYPE with number from this contact ( let's say "mobile" )? I have to update it using the userID acquired from the previous query, or how?
I just need to delete a single TYPE with number, other field of the contact must remain intact.
I am using this piece of code for obtaining contact :
int indexName = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int indexNumber = c
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int indexType = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
int indexID = c.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
String name = c.getString(indexName);
String number = c.getString(indexNumber);
String type = c.getString(indexType);
String typeStored = (String) Phone.getTypeLabel(mContext.getResources(), Integer.parseInt(type), "");
Log.i("TYPE READED : ", typeStored);
String id = c.getString(indexID);
where c is the cursor of the query.
Each number from same contact has it's own ID. You should use it for deleting. But you also need contact ID. You can get it using this line of code:
contactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
Then you delete the number using following code:
Cursor cur = contentResolver.query(RawContacts.CONTENT_URI,
new String[]{RawContacts._ID},
RawContacts.CONTACT_ID + "=?",
new String[] {contactID.toString()}, null);
int rowId=0;;
if(cur.moveToFirst()){
rowId = cur.getInt(cur.getColumnIndex(RawContacts._ID));
}
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String selectPhone = Data.RAW_CONTACT_ID + " = ? AND " +
Data.MIMETYPE + " = ? AND " +
Phone._ID + " = ?";
String[] phoneArgs = new String[] { Integer.toString(rowId),
Phone.CONTENT_ITEM_TYPE,
ID.toString()};
ops.add(ContentProviderOperation.newDelete(Data.CONTENT_URI)
.withSelection(selectPhone, phoneArgs).build());
try {
contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
The code to delete is a little long, the below does what it should with less lines of code
public static void deleteContact(ContentResolver contactHelper, String number) {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String[] args = new String[] { String.valueOf(getContactID(contactHelper, number)) };
ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI).withSelection(RawContacts.CONTACT_ID + "=?", args).build());
try {
contactHelper.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
e.printStackTrace();
} catch (OperationApplicationException e) {
e.printStackTrace();
}
}
I been working on an app that helps sending sms to your contacts. Everything is great, except that I'm supposed to add a "custom field number" to a contact such as "Work" or "Private". I'd search the web for answers and the ones that are useful for evryone, aren't for me. This is my code:
private void AddCtxtAttribute(int contactID, String contactNumber) {
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = ContentProviderOperation
.newInsert(Data.CONTENT_URI);
builder.withValue(Data.RAW_CONTACT_ID, contactID);
builder.withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
builder.withValue(ContactsContract.Data.DATA1, contactNumber);
builder.withValue(ContactsContract.Data.DATA2, Phone.TYPE_CUSTOM);
builder.withValue(ContactsContract.Data.DATA3, "My Custom Label");
ops.add(builder.build());
try {
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Log.e("RESULT", "Success! " + contactID + " - "
+ contactNumber);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("ERROR", "error : " + e.toString());
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("ERROR", "error : " + e.toString());
}
}
And it's called:
AddCtxtAttribute(contacto_id, contacto_numero);
where contacto_id and contacto_numero are a int and a String respectively.
The problem is that when I pressed the button, I have the ID (contacto_id) of that contact but it updates other contact. (like the id's don't match) but i've debug it and the id doesn't change.
Can anyone help me with this?
I figured it out!
the problem was that i was using diferent column names and uris in reading the contacts and inserting a new contact number.
I did this:
to query all contacts:
private void llenar_contactos() {
ProgressDialog progress;
lista_contactos_cel_sobrantes = null;
sobrantes = false;
lista_contactos_cel = new ArrayList<HashMap<String, Object>>();
progress = ProgressDialog.show(contactsActivity.this, "",
"Cargando Contactos. Porfavor espere...");
String[] projection = new String[] { Data.RAW_CONTACT_ID,
Phone.DISPLAY_NAME, Phone.NUMBER, Phone.LABEL };
String selection = Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'";
// ContactsContract.CommonDataKinds.Phone.HAS_PHONE_NUMBER + "='1'";
String sort_order = "display_name ASC";
Uri mContacts = Data.CONTENT_URI;
// ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
Cursor contacts = getContentResolver().query(mContacts, // Contact URI
projection, // Which columns to return
selection, // Which rows to return
null, // Where clause parameters
sort_order // Order by clause
);
total_contactos = contacts.getCount();
if (total_contactos > 0) {
int i = 0;
int multiplo = 0;
int indice_total = 0;
int temp_registros = 0;
String contact_id = "";
String name = "";
String phoneNo = "";
String label = "";
sobrantes = false;
int nameFieldColumnIndex = 0;
while (contacts.moveToNext()) {
nameFieldColumnIndex = contacts.getColumnIndex(Data.RAW_CONTACT_ID);
if (nameFieldColumnIndex > -1) {
contact_id = contacts.getString(nameFieldColumnIndex);
}
nameFieldColumnIndex = contacts.getColumnIndex(Phone.DISPLAY_NAME);
if (nameFieldColumnIndex > -1) {
name = contacts.getString(nameFieldColumnIndex);
}
nameFieldColumnIndex = contacts.getColumnIndex(Phone.NUMBER);
if (nameFieldColumnIndex > -1) {
phoneNo = contacts.getString(nameFieldColumnIndex);
}
nameFieldColumnIndex = contacts.getColumnIndex(Phone.LABEL);
if (nameFieldColumnIndex > -1) {
label = contacts.getString(nameFieldColumnIndex);
}
if(label != null){
Log.i("CONTACTO", "id: " + contact_id + " -> name: " + name
+ " ->number: " + phoneNo + " ->label: " + label);
} else {
Log.d("CONTACTO", "id: " + contact_id + " -> name: " + name
+ " ->number: " + phoneNo + " ->label: " + label);
}
}
contacts.close();
}
}
And to insert a new custom label:
private void AddCtxtAttribute(int contactID, String contactNumber) {
if (contactID != 0 && contactNumber != null) {
ArrayList<ContentProviderOperation> ops =
new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValue(Data.RAW_CONTACT_ID, contactID)
.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
.withValue(Phone.NUMBER, contactNumber)
.withValue(Phone.TYPE, Phone.TYPE_CUSTOM)
.withValue(Phone.LABEL, "My Custom Label")
.build());
try{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OperationApplicationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}