Tizen(Headed) Native API  6.5
Contacts

The Contacts Service API provides methods for managing contact information for people. A contact object is always associated with a specific address book. A person object is an aggregation of one or more contacts associated with the same person.

Required Header

#include <contacts.h>

Overview

The Contacts-service provides functions for managing contact information for people. A contact object is always associated with a specific address book. A person object is an aggregation of one or more contacts associated with the same person. Contacts-service has a relationship between Entities.

Contact_structure.png
Figure: Contact structure

There are three same contacts made from different address book. Person1 is an aggregation of Contact1, Contact2 and Contact3. The contacts-service provides an interface to manage the information

  • Managing contacts information stored in database
  • Aggregating contacts information from various accounts
  • Notifying changes of contacts information
  • Searching contacts information
  • vCard supports

Related Features

This API is related with the following features:

  • http://tizen.org/feature/contact
    It is recommended to design feature related codes in your application for reliability.
    You can check if a device supports the related features for this API by using System Information, thereby controlling the procedure of your application.
    To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.
    More details on featuring your application can be found from Feature Element.

Entities

Contacts-Service manages information related to following entities.

  • Contact
    • Information for individuals, like name, phone number, email, address, job, instant messenger, company, etc.
  • Account
    • Accounts are handled by account module. Contacts-service should use account ID which is created in the module.
    • Exceptionally, Local device address book has no account and its related account ID is zero.
    • Each account can create only one address book.
  • Address book
    • Represents where contacts and groups should belong to
    • Created by one of contacts sources below
      • Local device, which has no account.
      • Service providers such as Google or Yahoo, with account.
      • Applications like ChatON, Joyn, Facebook, etc.
  • Group
    • Grouped contacts on a same address book.
    • Groups and contacts have many-to-many relationship.
  • Person
    • A virtual contact that keeps merged information of contacts linked together.
    • When more than one contact from different sources designate same individual, then instead of showing each contacts separately, by Person concept, they can be shown and managed as one virtual contact.
    • Every contact becomes linked to at least one person.
  • My profile
    • My information which has almost same properties as contact information but it has no properties such as group relation, ringtone and message alert.
    • Single entry can be available on each address book.
  • Activity
    • Social activities are stored.
  • Speed Dial
    • Shortcut dialing number key information.
  • Phone Log
    • Call or message logs are stored.

Relationship between entities

Contacts-service has a relationship between Entities.

Relationship_between_entities.png
Figure: Relationship between entities

Relationship between Contact and Person

Person will be created automatically when inserting a contact record. Cannot create person record directly.

Sample code: Insert a contact record

 // create contact record
 contacts_record_h contact = NULL;
 contacts_record_create(_contacts_contact._uri, &contact);

 // add name
 contacts_record_h name = NULL;
 contacts_record_create(_contacts_name._uri, &name);
 contacts_record_set_str(name, _contacts_name.first, “test”);
 contacts_record_add_child_record(contact, _contacts_contact.name, name);

 // add number
 contacts_record_h number = NULL;
 contacts_record_create(_contacts_number._uri, &number);
 contacts_record_set_str(number, _contacts_number.number, “1234”);
 contacts_record_add_child_record(contact, _contacts_contact.number, number);

 // insert to database
 int contact_id = 0;
 contacts_db_insert_record(contact, &contact_id);

 // destroy record
 contacts_record_destroy(contact, true);
Creating_a_person_record.png
Figure: Creating a person record

Person record can be link to another person. Even though contacts address book is different, link is possible.

Sample code: Link contact

 int person_id1 = ... // acquire ID of Person1 record
 int person_id2 = ... // acquire ID of Person2 record

 contacts_person_link_person(person_id1, person_id2);
Link_person.png
Figure: Link person

Contact record can be separate from person record. New person will be created when unlinking contact record.

Sample code: Unlink contact

 int person_id1 = ... // acquire ID of Person1 record
 int contact_id3 = ... // acquire ID of Contact3 record

 contacts_person_unlink_contact(person_id1, contact_id3);
Unlink_contact.png
Figure: Unlink contact

Views

To access and handle entities, views are provided. According to data-view declarations, generic access functions are used (contacts_db_insert_record(), contacts_record_get_int(), …). Data-View is almost same as database “VIEW” which limits access and guarantees the performance by offering various views for the proper purpose. “Record” represents a single row of the data-views.
A data-view is a structure, which has property elements. For example, the _contacts_contact view describes the properties of the contact record. Its properties include name, company, nickname of the contact and many more.

Table: Contact editable views
View (Editable) Description
_contacts_address_book Describes the properties of the address book
_contacts_group Describes the properties of the group
_contacts_person Describes the properties of the person
_contacts_simple_contact Describes the properties of the contact
_contacts_contact Describes the properties of the contact
_contacts_my_profile Describes the properties of my profile
_contacts_name Describes the properties of the contacts name
_contacts_number Describes the properties of the contacts number
_contacts_email Describes the properties of the contacts email
_contacts_address Describes the properties of the contacts address
_contacts_note Describes the properties of the contacts note
_contacts_url Describes the properties of the contacts url
_contacts_event Describes the properties of the contacts birthday and anniversary
_contacts_group_relation Describes the properties of the contacts group relation
_contacts_relationship Describes the properties of the contacts relationship
_contacts_image Describes the properties of the contacts image
_contacts_company Describes the properties of the contacts company
_contacts_nickname Describes the properties of the contacts nickname
_contacts_messenger Describes the properties of the contacts messenger
_contacts_extension Describes the properties of the extension
_contacts_sdn Describes the properties of the service description number
_contacts_profile Describes the properties of the profile
_contacts_activity_photo Describes the properties of the photo of contacts activity
_contacts_activity Describes the properties of the contacts activity
_contacts_speeddial Describes the properties of the speed dial
_contacts_phone_log Describes the properties of the log
Table: Contact read only views
View (Read only) Description
_contacts_contact_updated_info used when identifying contact changes depending on version
_contacts_my_profile_updated_info used when identifying my profile changes depending on version
_contacts_group_updated_info used when identifying group changes depending on version
_contacts_group_member_updated_info used when identifying group member changes depending on version
_contacts_grouprel_updated_info used when identifying group relation profile changes depending on version
_contacts_person_contact used when querying to merge information of person and contact
_contacts_person_number used when querying to merge information of person and number
_contacts_person_email used when querying to merge information of person and email
_contacts_person_grouprel used when querying to merge information of person and group relation
_contacts_person_group_assigned used when querying for information of person who is assigned to group
_contacts_person_group_not_assigned used when querying for information of person who is not assigned to group
_contacts_person_phone_log used when querying to merge information of person and phone log
_contacts_person_usage used when querying for information of person usage
_contacts_contact_number used when querying to merge information of contact and number
_contacts_contact_email used when querying to merge information of contact and email
_contacts_contact_grouprel used when querying to merge information of contact and group relation
_contacts_contact_activity used when querying to merge information of contact and activity
_contacts_phone_log_stat used when querying for information of phone log status

Properties

Property elements have their data types and name.
Record types which have *_id as their properties, hold identifiers of other records - e.g. name, number and email views hold ID of their corresponding contacts in contact_id property (as children of the corresponding contacts record).
A type of some property is ‘record’. It means that the parent record can have child records. For example, a contact record has 'name', 'number' and 'email' properties, which means that records of those types can be children of contact type records.
In contacts_view.h header file, view macros are found and below figure shows what the macro means.

Properties.png
Figure: Properties

Sample code: Create a contact record then set caller ID

 contacts_record_h contact = NULL;
 contacts_record_create(_contacts_contact._uri, &contact);

 // set image to _contacts_contact view.
 contacts_record_h image = NULL;
 contacts_record_create(_contacts_image._uri, &image);

 char *resource_path = app_get_resource_path();
 char caller_id_path[1024] = {0};
 snprintf(caller_id_path, sizeof(caller_id_path), "%s/caller_id.jpg", resource_path);
 free(resource_path);
 contacts_record_set_str(image, _contacts_image.path, caller_id_path);

 // add image record to contact
 contacts_record_add_child_record(contact, _contacts_contact.image, image);
Note
For an application to insert private images in contacts, it needs to follow below conditions:
   1. Application must have privilege of http://tizen.org/privilege/contact.write to use APIs such as contacts_db_insert_record().
   2. Application's private directory and files must have 'read' permission of others, '644' for example. SMACK protects read permission from the other applications.
   3. Application may erase the image after destroying the contact record (contacts_record_destroy).

Records

In contacts-service, one of the basic concept is a record. It may be helpful to know that a record represents an actual record in the internal database, but in general, you can think of a record as a piece of information, like an address, phone number or group of contacts. A record can be a complex set of data, containing other data, e.g. an address record contains country, region, and street, among others.
Also, the contained data can be a reference to another record. For example, a contact record contains the 'address' property, which is a reference to an address record. An address record belongs to a contact record - its 'contact_id' property is set to identifier of the corresponding contact (more on IDs later). In this case, the address is the contacts child record and the contact is the parent record.
Effectively, a record can be a node in a tree or graph of relations between records.

URI

Each record type has a special structure defined for it, called 'view', which contains identifiers of its properties.
Every view has a special field - _uri - that uniquely identifies the view. In many cases you need to use the _uri value to indicate what type of record you wish to create or operate on.

APIs which needs _uri

 API int contacts_record_create(const char* view_uri, ...)
 API int contacts_filter_create(const char* view_uri, ...)
 API int contacts_query_create(const char* view_uri, ...)
 API int contacts_db_get_record(const char* view_uri, ...)
 API int contacts_db_delete_record(const char* view_uri, ...)
 API int contacts_db_get_all_records(const char* view_uri, ...)
 API int contacts_db_delete_records(const char* view_uri, ...)
 API int contacts_db_add_changed_cb(const char* view_uri, ...)
 API int contacts_db_remove_changed_cb(const char* view_uri, ...)
 API int contacts_db_get_changes_by_version(const char* view_uri, ...)
 API int contacts_db_search_records(const char* view_uri, ...)
 API int contacts_db_search_records_with_range(const char* view_uri, ...)
 API int contacts_db_get_count(const char* view_uri, ...)

Record handle

To use a record, you must obtain its handle. There are many ways to obtains it, including creating a new record and referring to child records of a record.
When creating a record, you need to specify what type of record you want to create. This is where you should use the URI property.

Sample code: Creates a contact record

 contacts_record_h contact = NULL;
 contacts_record_create(_contacts_contact._uri, &contact);

Sample code: Gets a contact record with id

 contacts_record_h contact = NULL;
 contacts_db_get_record(_contacts_contact._uri, id, &contact);

Basic types

A record can have basic properties of five types: integer, string, boolean, long integer, lli (long long int), double. Each property of basic type has functions to operate on it:

Table: Setter and getter functions
Property type Setter Getter
string contacts_record_set_str contacts_record_get_str
integer contacts_record_set_int contacts_record_get_int
boolean contacts_record_set_bool contacts_record_get_bool
long long integer contacts_record_set_lli contacts_record_get_lli
double contacts_record_set_double contacts_record_get_double

Above functions also require specifying which property you wish to get/set. Every getter and setter functions need record and property ID. You can make property ID by combine data-view name and property name. (.e.g. property ID of a contact display_name property : _contacts_contact.display_name)

Sample code : Sets the ‘ringtone_path’ property of a contact record.

 char *resource_path = app_get_resource_path();
 char ringtone_path[1024] = {0};
 snprintf(ringtone_path, sizeof(ringtone_path), "%s/ringtone.mp3", resource_path);
 free(resource_path);
 contacts_record_set_str(contact, _contacts_contact.ringtone_path, ringtone_path);

Note on returned values ownership: string getter function have the "_p" postfix. It means that the returned value should not be freed by the application, as it is a pointer to data in an existing record.

Sample code: Two ways of getting string property

 contacts_record_get_str(record, _contacts_person.display_name, &display_name);
 contacts_record_get_str_p(record, _contacts_person.display_name, &display_name);

In the first case, the returned string should be freed by the application. In second one, display_name value will freed automatically when destroying the record handle.

Child

A record can have properties of type 'record' called child records. A record can contain several records of a given type. For example, a ‘contact record’(parent) can contain many ‘address records’(children). The code below inserts an address record into a contact record. Note that it is not necessary to insert all records - just the contact record needs to be inserted into the database, it is enough for all information to be stored. Both records are then destroyed.

Sample code: Add child record

 contacts_record_h address = NULL;
 contacts_record_h image = NULL;
 int contact_id = 0;

 // image, address record can be child record of contact record
 contacts_record_create(_contacts_contact._uri, &contact);

 contacts_record_create(_contacts_image._uri, &image);
 char *resource_path = app_get_resource_path();
 char caller_id_path[1024] = {0};
 snprintf(caller_id_path, sizeof(caller_id_path), "%s/caller_id.jpg", resource_path);
 free(resource_path);
 contacts_record_set_str(image, _contacts_image.path, caller_id_path);
 contacts_record_add_child_record(contact, _contacts_contact.image, image);

 contacts_record_create(_contacts_address._uri, &address);
 contacts_record_set_str(address, _contacts_address.country, "Korea");
 contacts_record_add_child_record(contact, _contacts_contact.address, address);

 // insert contact to DBs
 contacts_db_insert_record(contact, &contact_id);
 contacts_record_destroy(contact, true);

Record ID property

ID is unique number which can identify a record Therefore, if you know the ID of a record, you can directly handle the record. The ID is read-only property, which is available after the record has been inserted into the database.

Sample code: Gets a contact record with id

 contacts_record_h contact = NULL;
 contacts_record_create(_contacts_contact._uri, &contact);

 contacts_record_h name = NULL;
 contacts_record_create(_contacts_name._uri, &name);
 contacts_record_set_str(name, _contacts_name.first, “first name”);
 contacts_record_add_child_record(contact, _contacts_contact.name, name);

 int contact_id = 0;
 contacts_db_insert_record(contact, &contact_id); // contact_id is unique number of contact record
 contacts_record_destroy(contact, true); // contact is no longer usable

 contacts_db_get_record(_contacts_contact._uri, contact_id, &contact); // contact is now a handle to the same record as before
 char *display_name = NULL;
 contacts_record_get_str(contact, _contacts_contact.display_name, &display_name);
 contacts_record_destroy(contact, true); // contact is no longer usable

Identifiers can also be used to establish a relation between two records. The following code sets an address record's 'contact_id' property to the ID of the contact. contact_id make relate between the address record and the contact which is identified by the contact_id. After that is done, the address becomes one of the addresses connected to the contact. The address is now the contacts child record, the contact is the parent record.

Sample code: Insert a address record with contact_id

 int contact_id = ... // acquire id of created contact
 int address_id = 0;
 contacts_record_create(_contacts_address._uri, &address);
 contacts_record_set_int(address, _contacts_address.contact_id, contact_id);
 // set other address properties
 // ...
 contacts_db_insert_record(address, &address_id);

Having a record handle, you can access all records of a specific type related to the given record.

Sample code: Gets a contact record

 int contact_id = ... // acquire id of created contact
 int address_num = 0;
 int i = 0;
 contacts_db_get_record(_contacts_contact._uri, contact_id, &contact);
 contacts_record_get_child_record_count(contact, _contacts_contact.address, &address_num);
 for (i = 0; i < address_num; i++) {
  contacts_record_h address = NULL;
  contacts_record_get_child_record_at_p(contact, _contacts_contact.address, i, &address);
  contacts_record_set_str(address, _contacts_address.country, "Korea");
 }
 contacts_db_update_record(contact);
 contacts_record_destroy(contact, true);

This example is to change a country of addresses which are child records of a contact. Each address can be traversed by using contacts_record_get_child_record_at_p(). It is possible to apply the changes by updating the contact which is the parent record.

Lists

The contacts-service provides functions which can handle list of same type records. Lists concept is based on standard doubly linked list. To operate a list, you must obtain its handle. The handle is provided during creation of the list. List handle must destroy after use.

 API int contacts_list_create(contacts_list_h* contacts_list);
 API int contacts_list_destroy(contacts_list_h contacts_list, bool delete_child);

If ‘delete_child’ parameter is the true, child resources will destroy automatically.

Sample code: Create a list handle

 // get list handle with query
 contacts_list_h list = NULL;
 contacts_list_create(&list);

 // use list
 //  ...

 contacts_list_destroy(list, true);

Sample code: Gets person list handle from database.

 // get list handle with query
 contacts_list_h list = NULL;
 contacts_db_get_all_records(_contacts_person._uri, 0, 0, &list);

 // use list
 // ...

 contacts_list_destroy(list, true);

Cursor

The list can be traversed by using cursor.

 API int contacts_list_first(contacts_list_h contacts_list);
 API int contacts_list_last(contacts_list_h contacts_list);
 API int contacts_list_next(contacts_list_h contacts_list);
 API int contacts_list_prev(contacts_list_h contacts_list);

You can get a record of current cursor.

Sample code: Loop list

 contacts_list_h list = NULL;
 contacts_record_h record = NULL;
 contacts_db_get_all_records(_contacts_person._uri, 0, 0, &list);
 do {
  contacts_list_get_current_record_p(list, &record);
  if (NULL == record)
   break;
  char *name = NULL;
  contacts_record_get_str_p(record, _contacts_person.display_name, &name);
  printf(“name=%s\n”, name);
 } while (CONTACTS_ERROR_NONE == contacts_list_next(list));
 contacts_list_destroy(list, true); // destroy child records automatically

Add / Remove

The contacts-service provides functions for adding/removing child record on list.

 API int contacts_list_add(contacts_list_h contacts_list, contacts_record_h record);
 API int contacts_list_remove(contacts_list_h contacts_list, contacts_record_h record);

Sample code: Adds records to the list

 contacts_record_h group1 = NULL;
 contacts_record_create(_contacts_group._uri, &group1);
 contacts_record_set_str(group1, _contacts_group.name, “group test1”);

 contacts_record_h group2 = NULL;
 contacts_record_create(_contacts_group._uri, &group2);
 contacts_record_set_str(group2, _contacts_group.name, “group test2”);

 contacts_list_h list = NULL;
 contacts_list_create(&list);

 // Adds records to the list
 contacts_list_add(list, group1);
 contacts_list_add(list, group2);

 contacts_db_insert_records(list, NULL, NULL);
 contacts_list_destroy(list, true);

Bulk APIs

Bulk APIs provide to insert/update/delete multiple records. There is no limit of record count on bulk API, but it causes a process to hang during the time the API is operated. Bulk APIs guarantee atomicity. That is, the API operating either all, or nothing.

 API int contacts_db_insert_records(contacts_list_h record_list, int **ids, int *count);
 API int contacts_db_update_records(contacts_list_h record_list);
 API int contacts_db_delete_records(const char* view_uri, int record_id_array[], int count);
 API int contacts_db_replace_records(contacts_list_h list, int record_id_array[], int count);

Sample code: Insert two contact records using bulk API.

 contacts_record_h contact1;
 contacts_record_create(_contacts_contact.uri, &contact1);

 // fill contact record
 // ...

 contacts_record_h contact2;
 contacts_record_create(_contacts_contact._uri, &contact2);

 // fill contact record
 // ...

 contacts_list_h list = NULL;
 contacts_list_create(&list);

 contacts_list_add(list, contact1);
 contacts_list_add(list, contact2);

 int **ids = NULL;
 int count = 0;

 // Insert contact records using bulk API
 contacts_db_insert_records(list, &ids, &count);

 // use ids
 // ...

 contacts_list_destroy(list, true);
 free(ids);

Queries

Queries are used to retrieve data which satisfies given criteria, like an integer property being greater than a given value, or a string property containing a given substring. Query needs a filter which can set the condition for search. The contacts-service provides query APIs for sorting, set projection and removing duplicated results.

Filter

The contacts Filter API provides the set of definitions and interfaces that enable application developers to make filters to set query.
When creating a filter, you need to specify what type of filter you want to create using _uri property. Filter handle must destroy after use.

 API int contacts_filter_create(const char* view_uri, contacts_filter_h* filter);
 API int contacts_filter_destroy(contacts_filter_h filter);

Sample code: Set filter condition to contain a given substring.

 contacts_filter_add_str(filter, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “1234”);

Sample code: Set filter condition to property value is true.

 contacts_filter_add_bool(filter, _contacts_person.is_favorite, true);

Conditions can be added to a filter. The conditions SHOULD be joined by using a AND and OR logical operator.

Sample code: Creates composite filter with OR operator.

 contacts_filter_add_str(filter1, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “1234”);
 contacts_filter_add_operator(filter1, CONTACTS_FILTER_OPERATOR_OR);
 contacts_filter_add_str(filter1, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “5678”);

Additionally, filters can join each other by using a AND and OR logical operator.

Sample code: Creates joined filter with AND operator.

 contacts_filter_add_str(filter1, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “1234”);
 contacts_filter_add_operator(filter1, CONTACTS_FILTER_OPERATOR_OR);
 contacts_filter_add_str(filter1, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “5678”);

 contacts_filter_add_bool(filter2, _contacts_person.is_fovorite, true);

 contacts_filter_add_operator(filter1, CONTACTS_FILTER_OPERATOR_AND);
 contacts_filter_add_filter(filter1, filter2);

Operator precedence in filters is determined by the order in which the conditions and filters are added. For example, if the following sequence is added:

Table: Filter and conditions
Filter with conditions Result
Contidion C1
OR
Contidion C2
AND
Condition C3
(C1 OR C2) AND C3
Filter F1:
Condition C1
OR
Condition C2

Filter F2:
Condition C3
OR
Condition C4

Filter F3:
Condition C5
AND
F1
AND
F2
(C5 AND F1) AND F2
Which is:
(C5 AND (C1 OR C2)) AND (C3 OR C4)

Sample code: Create a filter which will accept addresses with their contact's id equal to a given id (integer filter), or their country property equal to "Korea" (string filter). Create a query and add the filter to it. Results are received in a list.

 contacts_filter_h filter = NULL;
 contacts_list_h list = NULL;
 contacts_query_h query = NULL;

 contacts_filter_create(_contacts_address._uri, &filter);
 contacts_filter_add_int(filter, _contacts_address.contact_id, CONTACTS_MATCH_EQUAL, id);
 contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
 contacts_filter_add_str(filter, _contacts_address.country, CONTACTS_MATCH_EXACTLY, "Korea");
 contacts_query_create(_contacts_address._uri, &query);
 contacts_query_set_filter(query, filter);

 contacts_db_get_records_with_query(query, 0, 0, &list);

 contacts_filter_destroy(filter);
 contacts_query_destroy(query);

 // use the list
 // ...

 contacts_list_destroy(list, true);

Sort

Query results list can sort by property id.

 API int contacts_query_set_sort(contacts_query_h query, unsigned int property_id, bool is_ascending);

Sample code: Sort to query result by person id

 contacts_filter_add_str(filter, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, “Joe”);
 contacts_query_set_filter(query, filter);
 contacts_query_set_sort(query, _contacts_person.id, true);

 contacts_db_get_records_with_query(query, 0, 0, &list);

 contacts_query_destroy(query);
 contacts_filter_destroy(filter);
 contacts_list_destroy(person_list, true);

Projection

Projection allows you to query the Data for just those specific properties of a record that you actually need, at lower latency and cost than retrieving the entire properties.

 API int contacts_query_set_projection(contacts_query_h query, unsigned int property_ids[], int count)

Sample code: Creates a filter which will get only person id, display name, image thumbnail path from the person record with its vibration path has “test” (string filter). Create a query and add the filter to it. Results are received in a list.

 contacts_filter_add_str(filter, _contacts_person.vibration, CONTACTS_MATCH_CONTAINS, "test");
 contacts_query_set_filter(query, filter);

 //set projections to get
 unsigned int person_projection[] = {
  _contacts_person.id,
  _contacts_person.display_name,
  _contacts_person.image_thumbnail_path,
 };
 contacts_query_set_projection(query, person_projection, sizeof(person_projection)/sizeof(int));

 contacts_db_get_records_with_query(query, 0, 0, &person_list);

 // use list
 // ...

 contacts_query_destroy(query);
 contacts_filter_destroy(filter);
 contacts_list_destroy(person_list, true);

Distinct

If you query to some read-only view with set projection, result list can contain duplicates. You can remove duplicates using _contacts_query_set_distinct.

 API int contacts_query_set_distinct(contacts_query_h query, bool set)
 endcode

 Sample code: Remove duplicates
 @code
 unsigned int projection[] = {
 _contacts_person_number.person_id,
 _contacts_person_number.display_name,
 };
 contacts_filter_create(_contacts_person_number._uri, &filter);
 contacts_filter_add_bool(filter, _contacts_person_number.has_phonenumber, true);

 contacts_query_create(_contacts_person_number._uri, &query);
 contacts_query_set_projection(query, projection, sizeof(projection)/sizeof(int));
 contacts_query_set_filter(query, filter);

 // set distinct (remove duplicates)
 contacts_query_set_distinct(query, true);

 contacts_db_get_records_with_query(query, 0, 0, &list);

 // use list
 // ...

 contacts_list_destroy(list, true);
 contacts_query_destroy(query);
 contacts_filter_destroy(filter);

Database Change Notifications

Applications add/remove callback function to detect/ignore the contacts DB changes with contacts_db_add_changed_cb() / contacts_db_remove_changed_cb().
Clients wait contacts change notification on client side.
If contact is changed by another module, server publishes notification. The notification will be broadcast to subscribed modules. Finally, user callback function is called with user data.

Sample code: Register person changes notification callback

 // callback function
 static void __person_changed_cb(const char *view_uri, void *user_data)
 {
 // jobs for callback
 }
 // add changed noti callback
 contacts_db_add_changed_cb(_contacts_person._uri,  __person_changed_cb,  NULL);

vCard

Contacts-service provides methods for parsing and making vCard . vCard APIs based on vCard v3.0 specification. For more information about vCard, refer to rfc2426 (http://www.ietf.org/rfc/rfc2426.txt)

Parsing vCard

There are two ways for parsing vCard.

Sample code: Parsing vCard from stream then insert to database.

 // make contact record list from vcard stream
 contacts_list_h list = NULL;
 contacts_vcard_parse_to_contacts(vcard_stream, &list);

 int *ids = NULL;
 int count = 0;
 contacts_db_insert_records(list, &ids, &count);

 // use ids, count
 // ...

 free(ids);
 contacts_list_destroy(list, true);

Sample code: Parsing vCard from file then insert to database

 // called to get a record handle of _contacts_contact view
 static bool __vcard_parse_cb(contacts_record_h record, void *user_data)
 {
 int id = 0;
 contacts_db_insert_record(record, &id);

 // return false to break out of the loop
 // return true to continue with the next iteration of the loop
 return true;
 }

 // parse vCard from file
 char *resource_path = app_get_resource_path();
 char vcard_path[1024] = {0};
 snprintf(vcard_path, sizeof(vcard_path), "%s/vcard.vcf", resource_path);
 free(resource_path);
 contacts_vcard_parse_to_contact_foreach(vcard_path, __vcard_parse_cb, NULL);

Making vCard stream

You can make vcard stream from contact, person or my profile record.

Sample code: Makes vCard stream using contact record.

 contacts_record_h contact;
 char *vcard_stream = NULL;

 contacts_db_get_record(_contacts_contact._uri, contact_id, &contact);
 contacts_vcard_make_from_contact(contact, &vcard_stream);

 // use the vcard stream
 // ...

 free(vcard_stream);
 contacts_record_destroy(contact, true);