How to add new field(s) to the contact? - android

I want to add a Custom field to the ContactsContract content provider. I'm trying to build a Voip application and would like to add a SIP address(name#domain) field to it. What MIME type will I need to associate with it?
Also I want to add a group address field which will have a list of group addresses in it (name#domain, name#domain,...). Which MIME type will I have to associate with this type of field.
I also want to add custom fields to the Call History like a session ID and SIP address(name#domain) field. How can I customize the call history?
It'll be great if someone can give me an example.

You have to creat your own mime type for those.
Here is an example that saves a boolean as my custom mime type to the contacts. It uses the latest SDK 2.1
public void saveFormality() {
try {
ContentValues values = new ContentValues();
values.put(Data.DATA1, this.getFormality() ? "1" : "0");
int mod = ctx.getContentResolver().update(
Data.CONTENT_URI,
values,
Data.CONTACT_ID + "=" + this.getId() + " AND "
+ Data.MIMETYPE + "= '"
+ clsContacts.FORMALITY_MIMETYPE + "'", null);
if (mod == 0) {
values.put(Data.CONTACT_ID, this.getId());
values.put(Data.MIMETYPE, clsContacts.FORMALITY_MIMETYPE);
ctx.getContentResolver().insert(Data.CONTENT_URI, values);
}
} catch (Exception e) {
Log.v(TAG(), "saveFormality failed");
}
}

Related

Rename an account on Android (AccountManager)

I'm changing the name of a published app.
Is there a quick and safe way to change the account name created via AccountManager.addAccountExplicitly so that existing info will remain intact for existing users.
If not, how can I go about changing the account name manually while preserving all the data?
I'll post an answer of my naive approach of copying everything then deleting the old, but I'm sure someone will come up with a better one (or spot some bugs in my method).
API v21 added a renameAccount() method to the AccountManager, if that helps.
From the docs:
This is equivalent to removing the existing account and adding a new
renamed account with the old account's user data.
That means for backward compatibility, you would have to manually remove the account and run through the same procedure as creating a new one (AccountManager.addAccountExplicitly() and AccountManager.setUserData()) afterwards.
Edit:
If you want to update your contacts afterwards to display the correct account name, try this (untested) code:
ContentValues contentValues = new ContentValues();
contentValues.put(ContactsContract.RawContacts.ACCOUNT_NAME, "new account name");
getContext().getContentResolver().update(ContactsContract.RawContacts.CONTENT_URI,
contentValues,
ContactsContract.RawContacts.ACCOUNT_TYPE + " = ? AND " + ContactsContract.RawContacts.ACCOUNT_NAME + " = ?",
new String[]{"your account type", "old account name"});
A naive approach of going over all the records, copying them one by one, and deleting all the old stuff...
I'm really afraid this method might fail on real world users.
private void naiveRename(ContentResolver resolver) {
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
Cursor cur = resolver.query(RawContacts.CONTENT_URI, null, RawContacts.ACCOUNT_NAME + "='"
+ "OLD NAME" + "'", null, null);
if (cur != null) {
// copy all data
while (cur.moveToNext()) {
Uri curUri = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
.build();
ContentProviderOperation.Builder builder = ContentProviderOperation
.newInsert(curUri);
for (int i = 0; i < cur.getColumnCount(); i++) {
String colName = cur.getColumnName(i);
if (RawContacts._ID.equals(colName) || RawContacts.VERSION.equals(colName)
|| RawContacts.CONTACT_ID.equals(colName)) {
// Skip - read only
} else if (RawContacts.ACCOUNT_NAME.equals(colName)) {
builder.withValue(RawContacts.ACCOUNT_NAME, "NEW NAME");
} else {
builder.withValue(colName, cur.getString(i));
}
}
operationList.add(builder.build());
}
// delete all old data
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(RawContacts.CONTENT_URI);
builder.withSelection(RawContacts.ACCOUNT_NAME + "='" + "OLD NAME" + "'", null);
try {
resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (RemoteException e) {
// PANIC!
} catch (OperationApplicationException e) {
// OMG! WHAT TO DO?!
}
} else {
// LORDI!
}
}

Android change number to primary number

I'm trying to make someones number a primary number in the specific contact numbers. This is the code:
Cursor the_phone = _context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null, ContactsContract.CommonDataKinds.Phone.NUMBER +" = "+ numberToCall, null, null);
ContentValues values = new ContentValues();
if (the_phone.moveToFirst()){
values.put(ContactsContract.CommonDataKinds.Phone.LABEL,
the_phone.getString(the_phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.LABEL)));
values.put(ContactsContract.CommonDataKinds.Phone.IS_PRIMARY,1);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,numberToCall);
int phones = _context.getContentResolver().update(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,values, ContactsContract.CommonDataKinds.Phone.NUMBER +" = "+ numberToCall, null);
}
Then I keep getting the following:
03-27 08:18:27.009: E/AndroidRuntime(640): FATAL EXCEPTION: main
03-27 08:18:27.009: E/AndroidRuntime(640): java.lang.UnsupportedOperationException: URI: content://com.android.contacts/data/phones, calling user: com...
I checked the first query and it's working I'm able to find the number in the resolver but unable to update it.
ok actually solved after looking into the resolver class.
private Boolean editPrimary( Cursor phones , String contactId, String contactNumber, int primaryTo){
ArrayList ops = new ArrayList();
String where = ContactsContract.Data.CONTACT_ID + " = ? AND " +
ContactsContract.CommonDataKinds.Phone.MIMETYPE + " = ? AND " +
String.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE) + " = ? AND " +
ContactsContract.CommonDataKinds.Phone.NUMBER + " = ?";
String[] params = new String[] {contactId,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
String.valueOf(phones.getInt(phones.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.TYPE))),
contactNumber};
ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
.withSelection(where, params)
.withValue(ContactsContract.CommonDataKinds.Phone.IS_SUPER_PRIMARY,primaryTo)
.build());
try {
_context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
return true;
} catch (RemoteException e) {
e.printStackTrace();
return false;
} catch (OperationApplicationException e) {
e.printStackTrace();
return false;
}
}
from the developer guide we can see that :
Overview
ContactsContract defines an extensible database of contact-related information. Contact information is stored in a three-tier data model:
A row in the ContactsContract.Data table can store any kind of personal data, such as a phone number or email addresses. The set of data kinds that can be stored in this table is open-ended. There is a predefined set of common kinds, but any application can add its own data kinds.
A row in the ContactsContract.RawContacts table represents a set of data describing a person and associated with a single account (for example, one of the user's Gmail accounts).
A row in the ContactsContract.Contacts table represents an aggregate of one or more RawContacts presumably describing the same person. When data in or associated with the RawContacts table is changed, the affected aggregate contacts are updated as necessary.
so my first approach was wrong i didn't realize that the datakind class could represent the same data as the data class only directed to the context we are looking at

Update contact detail android

I am working on the an application in which I want to update contact of particular person. When I update only contact first and last name then it working fine but I want to update full detail of contact like email address, number, postal addres etc.
Please provide me some useful link. Thanks in advance.
each field (email, name, adress) has its on mime type, which you should use
in order to update the field.
lets try to update the email for instance.
First, you should find the detail you want to update.
we will work with Data table, where each Data.RAW_CONTACT_ID represents a detail
about some contact.
So, we need to find the Data.RAW_CONTACT_ID where the id is the id of the contact you want
to edit.
Now we need to find the mimetype (the specific row which represents the detail) of
email (Email.CONTENT_ITEM_TYPE).
The data of an email is stored in the column Email.DATA - there we put the new email.
if you want a specific email type, you should add it to the query:
for example, if you want to add a home-email, then you should add Email.TYPE_HOME
to the query.
then we build a query and finally apply the change.
Here's an examle:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
String emailParams = Data.RAW_CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ?";
String[] emailParamsWhere = new String[] { "contact_id", Email.CONTENT_ITEM_TYPE };
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI).withSelection(emailParams, emailParamsWhere).withValue(Email.DATA, "new email").withValue(Email.TYPE, Email.TYPE_HOME)
.build());
try
{
ContentProviderResult[] res = getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
if (res != null)
{
return true;
}
return false;
}
catch (RemoteException e)
{
Log.d(TAG, e.getMessage());
e.printStackTrace();
}
catch (OperationApplicationException e)
{
Log.d(TAG, e.getMessage());
e.printStackTrace();
}
For updating mobile phone, use this query:
String phoneParams = Data.RAW_CONTACT_ID + " = ? AND " + Data.MIMETYPE + " = ? AND " + Phone.TYPE + " = " + Phone.TYPE_MOBILE;
String[] phoneParamsWhere = new String[] { "contact_id", Phone.CONTENT_ITEM_TYPE };
ops.add(ContentProviderOperation.newUpdate(Data.CONTENT_URI).withSelection(phoneParams, phoneParamsWhere).withValue(Phone.NUMBER, "mobile_number")
.withValue(Phone.TYPE, Phone.TYPE_MOBILE).build());
Hope I helped

Find contacts with given display name

Learning Android I'm trying to find contacts using DISPLAY_NAME selector. I need to find all contacts with given name. Everything goes great using standard query, but falls when I use ContentProviderOperation. I do not understand some of features. When debugging i see exception: Empty values. But, which values I must insert there? Thanks.
op.add(ContentProviderOperation.newAssertQuery(ContactsContract.Contacts.CONTENT_URI)
.withSelection(ContactsContract.Contacts.DISPLAY_NAME + " = '" + name + "'", new String[] {ContactsContract.Contacts._ID})
.build());
try {
result = getContentResolver().applyBatch(ContactsContract.AUTHORITY, op);
} catch (Exception e) {
}
the problem is with your second line of code which should read:
.withSelection(
ContactsContract.Contacts.DISPLAY_NAME + " = ?",
new String[] {name}
)
To explain, the withSelection method takes two parameters, the selection string and an array selectionArgs, these are substituted into the selection string during query compilation. So in this example the ? is subtituted for the value of name. Text qualifiers (single quotes) are automatically embedded at the same time so no additional effort is required

Contact Custom Fields

Alright, I'm a little new to the Android SDK, so forgive me if my question doesn't make sense or is very trivial. I'd like to add a custom field for contacts, that contains the contacts username on a website I'm doing this app for. And, with this custom field, I'd like to have the ability to click it (like "Send message" or "Call mobile") so that I can go to a specif Activity in my application, with a TextView set with the username that I just clicked on.
Sorry if that is a bit confusing, if you need anything else let me know!
It's working! But I changed Data.CONTACT_ID to Data.RAW_CONTACT_ID here:
if (mod == 0) {
values.put(Data.CONTACT_ID, this.getId());
values.put(Data.MIMETYPE, clsContacts.FORMALITY_MIMETYPE);
ctx.getContentResolver().insert(Data.CONTENT_URI, values);
}
You have to creat your own mime type for those.
Here is an example that saves a boolean as my custom mime type to the contacts. It uses the latest SDK 2.1
public static final String MIMETYPE_FORMALITY = "vnd.android.cursor.item/useformality";
public clsMyClass saveFormality() {
try {
ContentValues values = new ContentValues();
values.put(Data.DATA1, this.getFormality() ? "1" : "0");
int mod = ctx.getContentResolver().update(
Data.CONTENT_URI,
values,
Data.CONTACT_ID + "=" + this.getId() + " AND "
+ Data.MIMETYPE + "= '"
+ clsContacts.FORMALITY_MIMETYPE + "'", null);
if (mod == 0) {
values.put(Data.CONTACT_ID, this.getId());
values.put(Data.MIMETYPE, clsContacts.FORMALITY_MIMETYPE);
ctx.getContentResolver().insert(Data.CONTENT_URI, values);
}
} catch (Exception e) {
Log.v(TAG(), "saveFormality failed");
}
return this;
}
public boolean getFormality() {
if (data.containsKey(FORMALITY)) {
return data.getAsBoolean(FORMALITY);
} else {
// read formality
Cursor c = readDataWithMimeType(clsContacts.MIMETYPE_FORMALITY, this.getId());
if (c != null) {
try {
if (c.moveToFirst()) {
this.setFormality(c.getInt(0) == 1);
return (c.getInt(0) == 1);
}
} finally {
c.close();
}
}
return false;
}
}
public clsMyClass setFormality(Boolean value) {
data.remove(FORMALITY);
data.put(FORMALITY, value);
return this;
}
/**
* Utility method to read data with mime type
*
* #param mimetype String representation of the mimetype used for this type
* of data
* #param contactid String representation of the contact id
* #return
*/
private Cursor readDataWithMimeType(String mimetype, String contactid) {
return ctx.getContentResolver().query(
Data.CONTENT_URI,
new String[] {
Data.DATA1
},
Data.RAW_CONTACT_ID + "=" + contactid + " AND " + Data.MIMETYPE + "= '" + mimetype
+ "'", null, null);
}
Usage is
objContact.setFormality(true).saveFormality();
To add custom field you need to add custom mimetype in MIMETYPE table. But we dont have direct access to MIMETYPE table. so following can be done:
public static final String MIMETYPE="vnd.android.cursor.item/favsong";
ContentValues values = new ContentValues();
values.put(Data.RAW_CONTACT_ID, id);
values.put(Data.MIMETYPE, MIMETYPE);
values.put(Data.DATA1, "MyFavSong");
Uri dataUri = getContentResolver().insert(Data.CONTENT_URI, values);
what we have done is , we have created a custom MIMETYPE as string constant.
Then using insert query we are inserting a new row in Data table having RAW_CONTACT_ID of a person we want to associate our custom field , in MIMETYPE column we put our own mimetype and in DATA1 column we put favourite song . here system internally add the new mimetype in MIMETYPE table and give it an ID and that ID is used in mimetype_id column of Data table.

Categories

Resources