In the 'old' days, you had to make 2 different interfaces to add contacts programmatically to Android.
There was an SDK3 and SDK5 solution (yes, that long ago). Now, you may use a single API to add contact information
to Android Contacts programmatically. As an FYI, I've developed Android, BREW, BlackBerry, J2ME, Palm OS, Symbian Series 40 and 60, iOS, Windows Mobile, Windows Phone and Windows 10 cross platform apps starting in 2002. The downside to the 'old' way is that you need WRITE_CONTACTS
permission (and sometimes READ_CONTACTS
) -these were triggered by using cr.applyBatch
.
Today, you can accomplish the same task without requiring those permissions by using an Intent. The 'trick' with the intent is in the intent.putExtra(Insert.POSTAL, addr)
and intent.putExtra(ContactsContract.Intents.Insert.Name, sName)
values ALONG WITH using the putParcelableArrayListExtra function
. Remember, you have to add the Insert.POSTAL
and Insert.NAME
along with the parcelable array.
Here is a sample that parses a VCard and opens the Contacts intent pre-populated with the data you need.
BPSocket.spit(string, char)
splits the string on the character (BPSocket abstracted this to be cross platform)
BBUtils.Utf8Decode(BPSocket.URLdecode(string))
- Again, abstracted calls to URL Decode the string (removing %xx, etc.) and then decoding that into UTF8 text (the string came from a url call).
public Uri AddVCard(String vCardData, Activity ctx) {
Uri newContactUri = null;
ArrayList<ContentValues> data = new ArrayList<ContentValues>();
String[] arSplit = BPSocket.split(vCardData, '&');
String sOrg = "";
String sTitle = "";
Intent intent = new Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI);
for (int i=0; i<arSplit.length; i++) {
String keyv = arSplit[i];
int ixEq = keyv.indexOf('=');
if (ixEq != -1 && ixEq < keyv.length() - 1) {
String decoded = BBUtils.Utf8Decode(BPSocket.URLdecode(keyv.substring(ixEq + 1)));
if (keyv.startsWith("N=")) {
boolean bAdd = false;
String sFirst = "";
String sLast = "";
String[] arNames = BPSocket.split(decoded, ';'); // last;first;prefix;suffix
ContentValues nameValues = new ContentValues();
nameValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
if (arNames.length > 0) { // FAMILY_NAME
sLast = arNames[0];
nameValues.put(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, sLast);
bAdd = true;
}
if (arNames.length > 1) { // GIVEN_NAME
sFirst = arNames[1];
nameValues.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, sFirst);
bAdd = true;
}
if (arNames.length> 2) { // PREFIX
nameValues.put(ContactsContract.CommonDataKinds.StructuredName.PREFIX, arNames[2]);
bAdd = true;
}
if (arNames.length > 3) { // SUFFIX
nameValues.put(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, arNames[3]);
bAdd = true;
}
if (bAdd) {
String sName = "";
if (sFirst.length()> 0)
sName += sFirst;
if (sLast.length() > 0) {
if (sName.length() > 0)
sName += " ";
sName += sLast;
}
if (sName.length() > 0) {
nameValues.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, sName);
intent.putExtra(ContactsContract.Intents.Insert.NAME, sName);
}
data.add(nameValues);
}
} else if (keyv.startsWith("TITLE=")) {
sTitle = decoded;
} else if (keyv.startsWith("ORG=")) { // org name;level1;level2
sOrg = decoded;
} else if (keyv.startsWith("EMAIL")) {
ContentValues emailValues = new ContentValues();
emailValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
emailValues.put(ContactsContract.CommonDataKinds.Email.TYPE, ContactsContract.CommonDataKinds.Email.TYPE_WORK);
emailValues.put(ContactsContract.CommonDataKinds.Email.ADDRESS, decoded);
data.add(emailValues);
} else if (keyv.startsWith("TEL")) {
// vcard: home,msg,work,pref,voice,fax,cell,video,pager,bbs,modem,car
// we support: WORK, FAX, CELL, MSG, HOME, FAX
boolean bAdd = false;
ContentValues telValues = new ContentValues();
telValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
if (keyv.indexOf("WORK") != -1) {
telValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
bAdd = true;
} else if (keyv.indexOf("CELL") != -1) {
telValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
bAdd = true;
} else if (keyv.indexOf("MSG") != -1) {
telValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_PAGER);
bAdd = true;
} else if (keyv.indexOf("HOME") != -1) {
telValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
bAdd = true;
} else if (keyv.indexOf("FAX") != -1) {
telValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_FAX_WORK);
bAdd = true;
}
if (bAdd) {
telValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, decoded);
data.add(telValues);
}
} else if (keyv.startsWith("NICKNAME=")) {
ContentValues nickValues = new ContentValues();
nickValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
nickValues.put(ContactsContract.CommonDataKinds.Nickname.NAME, decoded);
data.add(nickValues);
} else if (keyv.startsWith("NOTE=")) {
ContentValues noteValues = new ContentValues();
noteValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
noteValues.put(ContactsContract.CommonDataKinds.Note.NOTE, decoded);
data.add(noteValues);
} else if (keyv.startsWith("ADR=")) {
// ADR dom,intl,postal,parcel,home,work,pref =po box;extended addr;street addr;locality(city);region(state);zip;country
// ADR-WORK=
// ADR-HOME=
// ADR - default to Work
String sAddr = "";
String[] arAddr = BPSocket.split(decoded, ';');
ContentValues addrValues = new ContentValues();
addrValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
if (arAddr.length > 0) { // po box
sAddr = arAddr[0];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.POBOX, arAddr[0]);
}
if (arAddr.length > 2) { // street addr
sAddr = arAddr[2];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, arAddr[2]);
}
if (arAddr.length > 3) { // locality
if (sAddr.length() > 0)
sAddr += ", ";
sAddr += arAddr[3];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, arAddr[3]);
}
if (arAddr.length > 4) { // region
if (sAddr.length() > 0)
sAddr += ", ";
sAddr += arAddr[4];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, arAddr[4]);
}
if (arAddr.length > 5) { // zip
if (sAddr.length() > 0)
sAddr += " ";
sAddr += arAddr[5];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, arAddr[5]);
}
if (arAddr.length > 6) { // county
if (sAddr.length() > 0)
sAddr += ", ";
sAddr += arAddr[6];
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, arAddr[6]);
}
if (keyv.indexOf("HOME") != -1) {
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, ContactsContract.CommonDataKinds.StructuredPostal.TYPE_HOME);
} else {
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, ContactsContract.CommonDataKinds.StructuredPostal.TYPE_WORK);
}
if (sAddr.length() > 0) {
addrValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, sAddr);
intent.putExtra(Insert.POSTAL, sAddr);
}
data.add(addrValues);
}
}
}
if (sTitle.length() > 0 || sOrg.length() > 0) {
ContentValues orgValues = new ContentValues();
orgValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
if (sOrg.length() > 0)
orgValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, sOrg);
if (sTitle.length() > 0)
orgValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, sTitle);
data.add(orgValues);
}
intent.putParcelableArrayListExtra(Insert.DATA, data);
ctx.startActivity(intent);
return newContactUri;
}