I am developing a backup application for Android, mainly contacts and SMS messages. Backing up isn't a problem, but writing the contacts back to the Android database is proving problematic.
This is what I have so far:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, 1)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.GIVEN_NAME, "Joe")
.withValue(StructuredName.FAMILY_NAME, "Bloggs")
.build());
ops.add(ContentProviderOperation.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID,1)
.withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "086555555")
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.build());
try{
ctx.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
}catch(Exception e){
e.printStackTrace();
}
It all seems to hinge on the RAW_CONTACT_ID. I'm using the emulator, with no contacts at the start. It works for the first contact creation(RAW_CONTACT_ID = 0), but no contacts seem to be created after that initial one, where RAW_CONTACT_ID is 1 upwards. Anybody got any ideas as to how this is the case?
What I did was I created my contact first and then grabbed the ID of that newly created contact and added all the other contact details to that ID
Here is my frist step, create the new contact, then find the ID of that contact
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, prefix)
.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName)
.withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, middleName)
.withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName)
.withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, suffix)
.build());
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
Cursor cursor = null;
try
{
cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, baseProjection, ContactsContract.Contacts.DISPLAY_NAME + " = ? ", new String[] {displayname}, __DEFAULT_SORT_ORDER);
if (cursor.moveToFirst())
{
String val;
val = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
return val;
}
}
...
Then I add any detail to the contact I want like this:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValue(ContactsContract.Data.CONTACT_ID, contactId)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.Data.DATA5, poBox)
.withValue(ContactsContract.Data.DATA4, street)
.withValue(ContactsContract.Data.DATA7, city)
.withValue(ContactsContract.Data.DATA8, region)
.withValue(ContactsContract.Data.DATA9, postCode)
.withValue(ContactsContract.Data.DATA10, country)
.withValue(ContactsContract.Data.DATA2, type)
.withValue(ContactsContract.Data.DATA3, label)
.build());
Related
This is the problem I am facing. I already have a contact named "Frank" in my contact. I need to add a new contact named "Frank". However, If I add using the below method, The new number gets added to the existing "Frank contact".
How to properly add contacts with the same name?
ArrayList<ContentProviderOperation> ops = new ArrayList<>();
int rawContactInsertIndex = ops.size();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, HelperMethods.capitalize(name_et.getText().toString()))
.build());
ops.add(ContentProviderOperation.
newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number_et.getText().toString())
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM)
.withValue(ContactsContract.CommonDataKinds.Phone.LABEL, phone_label_spinner.getSelectedItem().toString())
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
Found the answer from here: Android not adding all contacts with duplicate fields
Adding AGGREGATION_MODE column will work.
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DISABLED)
.build());
I developing an app in which I need to store data related to a contact.
I list the contacts in a recycleView using a cursor and each itemView has a star button to set the contact as favorite (not the same as the system).
I managed to store the data in ContactsContract.Data, doing this:
private void addContactData(long contactId, String displayName, boolean favorite) {
// displayName same as the value for Contacts.DISPLAY_NAME_PRIMARY
ArrayList<ContentProviderOperation> ops =
new ArrayList<>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, CUSTOM_ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, CUSTOM_ACCOUNT_NAME)
.withValue(ContactsContract.RawContacts.CONTACT_ID, contactId)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
.build());
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, CustomData.CONTENT_ITEM_TYPE)
.withValue(CustomData.IS_FAVORITE, favorite)
.build());
try {
ContentProviderResult[] contentProviderResults = cr.applyBatch(ContactsContract.AUTHORITY, ops);
return contactUri;
} catch (RemoteException | OperationApplicationException e) {
Log.e(getClass().getSimpleName(), e.getMessage(), e);
return null;
}
}
The problem I have is when two contacts have the exact same name ej. "Tom" and "Tom" if I press the fav button, is adding a third contact that is even listed in the device contacts app.
Some search guied me to add more data to distinguish the contacts using:
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.build());
// OR
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)
.build());
And it worked just fine, except if the fields are equals in both contacts. What do I need to avoid this behavior, and Why the CONTACT_ID isn't enough to do this kind of operations?
You need to tell Android to merge the new RawContact you've just created with some (one or more) existing RawContacts.
You do that using the AggregationException table, adding a row for each such "link".
See: https://stackoverflow.com/a/40869351/819355
Code snippet:
Builder builder = ContentProviderOperation.newUpdate(AggregationExceptions.CONTENT_URI);
builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_TOGETHER);
builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, yourNewRawContact);
builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, someExistingRawContact);
ContentProviderOperation op = builder.build();
I want my android app's connection to be added in an existing contact. I am sending my all contacts of Phonebook to server(with Name,Phone Number, and Contact ID) to check which contacts are registered for my app. I will send back to client app the contact IDs which are matched.
Now I want to add connection to those contacts in my Phonebook based on those returned IDs.
How can I add app connection by editing the contact based on one of returned contact ID?
Thanks
Try with this code, it will give you desired output
public static void addContact(Context context, MyContact contact) {
ContentResolver resolver = context.getContentResolver();
// add condition that you want to check
String where= RawContacts.ACCOUNT_TYPE + " = ? AND " +RawContacts.DISPLAY_NAME_PRIMARY+"=?";
//values of that condotion
String[] value=new String[] { AccountGeneral.ACCOUNT_TYPE ,contact.name};
resolver.delete(RawContacts.CONTENT_URI, where, value);
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(RawContacts.CONTENT_URI, true))
.withValue(RawContacts.ACCOUNT_NAME, AccountGeneral.ACCOUNT_NAME)
.withValue(RawContacts.ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE)
//.withValue(RawContacts.SOURCE_ID, 12345)
//.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED)
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Settings.CONTENT_URI, true))
.withValue(RawContacts.ACCOUNT_NAME, AccountGeneral.ACCOUNT_NAME)
.withValue(RawContacts.ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE)
.withValue(Settings.UNGROUPED_VISIBLE, 1)
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.GIVEN_NAME, contact.name)
.withValue(StructuredName.FAMILY_NAME, contact.lastName)
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "12342145")
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.DATA, "sample#email.com")
.build());
ops.add(ContentProviderOperation.newInsert(addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, MIMETYPE)
.withValue(Data.DATA1, 12345)
.withValue(Data.DATA2, "sample")
.withValue(Data.DATA3, "sample")
.build());
try {
ContentProviderResult[] results = resolver.applyBatch(ContactsContract.AUTHORITY, ops);
i++;
if (results.length == 0)
;
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Account type id
*/
public static final String ACCOUNT_TYPE = "com.test.app";
/**
* Account name
*/
public static final String ACCOUNT_NAME = "Test";
public static void addContact(Context context, User contact) {
ContentResolver resolver = context.getContentResolver();
resolver.delete(RawContacts.CONTENT_URI, RawContacts.ACCOUNT_TYPE
+ " = ?", new String[] { AccountConstants.ACCOUNT_TYPE });
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(
RawContacts.CONTENT_URI, true))
.withValue(RawContacts.ACCOUNT_NAME,
AccountConstants.ACCOUNT_NAME)
.withValue(RawContacts.ACCOUNT_TYPE,
AccountConstants.ACCOUNT_TYPE)
// .withValue(RawContacts.SOURCE_ID, 12345)
// .withValue(RawContacts.AGGREGATION_MODE,
// RawContacts.AGGREGATION_MODE_DISABLED)
.build());
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(Settings.CONTENT_URI,
true))
.withValue(RawContacts.ACCOUNT_NAME,
AccountConstants.ACCOUNT_NAME)
.withValue(RawContacts.ACCOUNT_TYPE,
AccountConstants.ACCOUNT_TYPE)
.withValue(Settings.UNGROUPED_VISIBLE, 1).build());
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.GIVEN_NAME, contact.getFullname())
.withValue(StructuredName.FAMILY_NAME, contact.getFullname())
.build());
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER,
contact.getPhoneNumber()).build());
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Email.DATA,
contact.getEmail()).build());
ops.add(ContentProviderOperation
.newInsert(
addCallerIsSyncAdapterParameter(Data.CONTENT_URI, true))
.withValueBackReference(Data.RAW_CONTACT_ID, 0)
.withValue(Data.MIMETYPE, MIMETYPE)
.withValue(Data.DATA1, contact.getFullname())
.withValue(Data.DATA2, contact.getEmail())
.withValue(Data.DATA3, contact.getHomeAddress()).build());
try {
ContentProviderResult[] results = resolver.applyBatch(
ContactsContract.AUTHORITY, ops);
if (results.length == 0)
AppLog.d(TAG, "Failed to add.");
} catch (Exception e) {
AppLog.e(TAG, e.getMessage(), e);
}
}
Problem - Currently the code is adding new contact but not merging it into existing contact based on Phone number. Is there anything I have to do before adding the contact? I would like to display my app account inside Contact same as Whats App.
I have implemented SyncService, SyncAdapter, Authenticator, contacts.xml and other classes required for the project. The only thing not working is showing contact inside the default Contact app instead of creating new contact.
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android" >
<ContactsDataKind
android:detailColumn="data2"
android:detailSocialSummary="true"
android:icon="#drawable/ic_launcher"
android:mimeType="vnd.android.cursor.item/com.test.app"
android:summaryColumn="data3" />
</ContactsSource>
I had the same problem on Android 6.1 and as I heard, this issue is present since Lollipop. Every implementation on the web shows that the contact matching should work based on phone number. And it works on earlier systems - I tried it on KitKat and it works like a charm. But since Android 5.0 contacts don't match somehow.
Fortunately phone number is not the only parameter the matching depends on - there is also displayname. So the working implementation should look like this:
// as displayName pass the retrieved ContactsContract.Contacts.DISPLAY_NAME
#Override
public void addContact(#Nonnull final String displayName, #Nonnull final String phone) {
final ContentResolver resolver = context.getContentResolver();
final ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.RawContacts.CONTENT_URI, true))
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, ACCOUNT_NAME)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, ACCOUNT_TYPE)
.withValue(ContactsContract.RawContacts.AGGREGATION_MODE,
ContactsContract.RawContacts.AGGREGATION_MODE_DEFAULT)
.build());
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.build());
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
.build());
ops.add(ContentProviderOperation
.newInsert(addCallerIsSyncAdapterParameter(ContactsContract.Data.CONTENT_URI, true))
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, YOUR_MIMETYPE)
.withValue(ContactsContract.Data.DATA1, 12345)
.withValue(ContactsContract.Data.DATA2, "user")
.withValue(ContactsContract.Data.DATA3, "action")
.build());
try {
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (Exception e) {
e.printStackTrace();
}
}
I left the phoneNumber in case the contact doesn't have any displayname - then it would at least match on earlier Android versions.
i want to enter contact list: "contact_name" , and "contact_number" into phone's contact list i used following code for that :
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
.build());
//------------------------------------------------------ Names
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name).build());
//------------------------------------------------------ Mobile Number
ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.withValue(ContactsContract.CommonDataKinds.Phone.TYPE,
ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)
.build());
// Asking the Contact provider to create a new
// contact
try
{
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
}
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Exception: " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
it run successfully, but i want to prevent insertion of duplicate entry,
for that i have used below link but could not find out proper solution
contact exists in contacts