Contacts: Managing Contacts and Groups, and Accessing the Contact Database
This tutorial demonstrates how you can manage contacts and groups, and import them to or export them from the vCard format.
This feature is supported in mobile applications only.
Warm-up
Become familiar with the Contacts API basics by learning about:
-
Initializing Contacts
Initialize the contacts for use.
- Contacts
-
Creating a Contact
Create a new contact.
-
Setting Contact Properties
Set contact properties, such as name and image.
-
Inserting a Contact to the Database
Insert a contact to the Contacts database.
-
Getting Contacts
Retrieve single contacts or a list of contacts.
-
Updating a Contact
Update contact details.
-
Deleting a Person
Delete the person from the database.
-
Linking and Unlinking Contacts
Link and unlink contacts to persons.
-
Managing Favorites
Set or unset a person to be a favorite.
-
Monitoring Person Changes
Receive notifications when changes occur in persons.
-
Creating a Contact
- Groups
-
Creating a Group
Create a new group.
-
Setting Group Properties
Set group properties, such as name and image.
-
Inserting a Group to the Database
Insert a group to the Contacts database.
-
Getting Groups
Retrieve single groups or a list of groups.
-
Updating a Group
Update group details.
-
Deleting a Group
Delete the group from the database.
-
Managing Group Members
Add, remove, and retrieve group members.
-
Monitoring Group Changes
Receive notifications when changes occur in groups.
-
Creating a Group
- vCards
-
Making a vCard
Make a vCard stream from a person record.
-
Parsing a vCard
Parse a vCard from a file and insert to the database.
-
Making a vCard
- Speed dials
-
Creating a Speed Dial
Create a new speed dial.
-
Setting Speed Dial Properties
Set speed dial properties, such as speed dial number and number ID.
-
Inserting a Speed Dial to the Database
Insert a speed dial to the database.
-
Getting Speed Dials
Retrieve a single speed dial or a list of speed dials.
-
Updating a Speed Dial
Update speed dial details.
-
Deleting a Speed Dial
Delete the speed dial from the database.
-
Creating a Speed Dial
- Phone logs
-
Creating a Log
Create a new log.
-
Setting Log Properties
Set log properties, such as type, time, and address.
-
Inserting a Log to the Database
Insert a log to the database.
-
Getting Logs
Retrieve single log or a list of logs.
-
Deleting a Log
Delete the log from the database.
-
Creating a Log
Follow-up
Once we have learned the basics of the Contacts API, we can now move on to more advanced tasks, including:
- Records
-
Inserting New Records
Add new records to the database.
-
Getting Record Details
Get information from existing records.
-
Handling Lists
Iterate, filter, and sort record lists.
-
Deleting Records
Remove records from the database.
-
Linking Persons
Assign several contacts to one person.
-
Inserting New Records
- Contact settings
-
Managing Contact Settings
Change the display settings of contacts.
-
Managing Contacts on the SIM Card
Check that the SIM card is initialized and import contacts from the SIM card.
-
Managing Contact Settings
- vCard information
-
Importing from vCard
Import contacts from vCard files.
-
Exporting to vCard
Export contacts to vCard files.
-
Importing from vCard
Initializing Contacts
To start with the Contact Service:
-
To use the functions and data types of the Contacts API, include the <contacts.h> header file in your application:
#include <contacts.h>
- Most of the API functions return error codes, therefore define at the beginning of your code the int type, which is used to store error codes. Each time when a function returns error codes, verify the result of the operation.
-
Call the contacts_connect() function, which connects your application with the Contact Service. Without this function, you cannot get access to the Contacts database.
int error_code; error_code = contacts_connect();
- When the Contacts APIs are not needed anymore, you have to disconnect from the service using the contacts_disconnect() function:
error_code = contacts_disconnect();
Creating a Contact
Before you insert a record, you need to create a record handle. To create it and assign a new record:
contacts_record_h contact; error_code = contacts_record_create(_contacts_contact._uri, &contact);
The first argument determines the type of the created record. Use _contacts_contact._uri to create contact type records.
This record, however, contains no additional information, like a name or phone number. To add them, you must set contact properties by creating additional records and setting them as child records of the contact record. Note that records created this way are objects in the memory, with contacts_record_h type variables as their handles. Changes made to these objects are not reflected in the database until your explicit request, using contacts_db_insert_record() or contacts_db_update_record().
Setting Contact Properties
To set the contact name, birthday, and phone number:
- Add the contact name.
- Create a name record:
contacts_record_h name; error_code = contacts_record_create(_contacts_name._uri, &name);
- To set the first name, set the value of a string type property identified by _contacts_name.first.
error_code = contacts_record_set_str(name, _contacts_name.first, "John");
The contacts_record_set_str() function is used to set string field values. There are other similar functions for other types, such as integer and double. The name variable is the record handle created above. The second argument – _contacts_name.first – is the property identifier, and the third argument is the value to be assigned.
- Set the last name similarly:
error_code = contacts_record_set_str(name, _contacts_name.last, "Smith");
- Associate the name record with the contact record, by setting the name as the contact's child record. In this example, it is achieved using contacts_record_add_child_record().
error_code = contacts_record_add_child_record(contact, _contacts_contact.name, name);
The second argument (_contacts_contact.name) is the parent property to which the child record is assigned. See _contacts_contact view description in the Contacts API. In the API, the name property is listed as one of the record type properties, which means that other records can be assigned to this property as child records ("single" means that only 1 _contacts_name type child record is allowed). The required type of the child record is specified in the API.
- Create a name record:
- Add an image.
- Create an image record:
contacts_record_h image; error_code = contacts_record_create(_contacts_image._uri, &image);
- To set the image, set the value of a string type property identified by _contacts_image.path:
char *resource_path = app_get_resource_path(); char caller_id_path[1024]; snprintf(caller_id_path, sizeof(caller_id_path), "%s/caller_id.jpg", resource_path); free(resource_path); error_code = contacts_record_set_str(image, _contacts_image.path, caller_id_path);
- Set the image record as the contact's child record:
error_code = contacts_record_add_child_record(contact, _contacts_contact.image, image);
- Create an image record:
- Add an event.
You can add a birthday event associated with the contact. An event contains the date and the event type, among other properties.
- Create an event record:
contacts_record_h event; error_code = contacts_record_create(_contacts_event._uri, &event);
- Set the event date. The date is an integer, equal to year * 10000 + month * 100 + day.
int year = 1990; int month = 5; int day = 21; int int_date = year * 10000 + month * 100 + day; error_code = contacts_record_set_int(event, _contacts_event.date, int_date);
- Set the event type to birthday. For available types, see contacts_event_type_e enumeration.
error_code = contacts_record_set_int(event, _contacts_event.type, CONTACTS_EVENT_TYPE_BIRTH);
- If the type is CONTACTS_EVENT_TYPE_CUSTOM, you can set a custom label (see _contacts_event view).
error_code = contacts_record_set_int(event, _contacts_event.type, CONTACTS_EVENT_TYPE_CUSTOM); error_code = contacts_record_set_str(event, _contacts_event.label, "Event description");
- Set the event record as the contact's child record:
error_code = contacts_record_add_child_record(contact, _contacts_contact.event, event);
- Create an event record:
- Add a phone number.
The phone number is added to a parent record using an alternative method.
- Create a phone number record and set the number property:
contacts_record_h number; error_code = contacts_record_create(_contacts_number._uri, &number); error_code = contacts_record_set_str(number, _contacts_number.number, "+8210-1234-5678");
- Set the number record as the contact's child record:
error_code = contacts_record_add_child_record(contact, _contacts_contact.number, number);
- Create a phone number record and set the number property:
Inserting a Contact to the Database
To insert a contact:
-
When the data is set for the contact and name records, you can insert them into the database. When you insert a parent record, all child records added to it using contacts_record_add_child_record() are inserted automatically.
Insert a contact record:
int id = -1; error_code = contacts_db_insert_record(contact, &id);
- When the records are in the database, the objects representing them in the memory are no longer needed and must be destroyed.
contacts_record_destroy(contact, true);
If the second parameter is true, child records of the given record (objects representing them in the memory) are also destroyed. This does not depend on the way the child records were added.
Getting Contacts
To retrieve contact records:
-
A person is an aggregation of one or more contacts associated with the same person. The person is created automatically when inserting a contact record. To use the contact information in your application, you must learn to print basic person information.
To get a single person record:
-
Use the contacts_db_get_record() function with the appropriate person_id:
contacts_record_h person = NULL; const int person_id = ... // Acquire person ID int error_code; error_code = contacts_db_get_record(_contacts_person._uri, person_id, &person);
- When you no longer need the person record, destroy the used structures:
contacts_record_destroy(speeddial, true);
-
- To get the total person record list:
-
Use the contacts_db_get_all_records() function:
contacts_list_h list = NULL; error_code = contacts_db_get_all_records(_contacts_person._uri, 0, 0, &list);
-
Iterate the list and read the records.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. -
To get the records from the list, use the contacts_list_get_current_record_p(), and contacts_list_next() or contacts_list_prev() functions. Get the details of each record in the loop.
contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { char* display_name; error_code = contacts_record_get_str_p(record, _contacts_person.display_name, &display_name); dlog_print(DLOG_DEBUG, LOG_TAG, "display_name: %s", display_name); error_code = contacts_list_next(list); }
- If you want to get more details of each record, use the contacts_gl_person_data_t structure like below:
contacts_gl_person_data_t *gl_person_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_person_data = _create_gl_person_data(record); // You can get, for example, display name: // gl_person_data->display_name _free_gl_person_data(gl_person_data); error_code = contacts_list_next(list); }
- The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
typedef struct _contacts_gl_person_data { int id; char *display_name; char *default_phone_number; contacts_list_h associated_contacts; } contacts_gl_person_data_t; static void _free_gl_person_data(contacts_gl_person_data_t *gl_person_data) { if (NULL == gl_person_data) return; free(gl_person_data->display_name); free(gl_person_data->default_phone_number); contacts_list_destroy(gl_person_data->associated_contacts, true); free(gl_person_data); } static contacts_gl_person_data_t* _create_gl_person_data(contacts_record_h record) { contacts_gl_person_data_t *gl_person_data; gl_person_data = malloc(sizeof(contacts_gl_person_data_t)); memset(gl_person_data, 0x0, sizeof(contacts_gl_person_data_t)); if (contacts_record_get_int(record, _contacts_person.id, &gl_person_data->id) != CONTACTS_ERROR_NONE) { dlog_print(DLOG_ERROR, LOG_TAG, "get person id failed "); _free_gl_person_data(gl_person_data); return NULL; } if (false == _get_display_name(record, &gl_person_data->display_name)) { dlog_print(DLOG_ERROR, LOG_TAG, "_get_display_name() failed "); _free_gl_person_data(gl_person_data); return NULL; } if (false == _get_default_phone_number(record, &gl_person_data->default_phone_number)) { dlog_print(DLOG_ERROR, LOG_TAG, "_get_default_phone_number() failed "); _free_gl_person_data(gl_person_data); return NULL; } if (false == _get_associated_contacts(record, &gl_person_data->associated_contacts)) { dlog_print(DLOG_ERROR, LOG_TAG, "_get_associated_contacts() failed "); _free_gl_person_data(gl_person_data); return NULL; } _print_phone_numbers(gl_person_data->associated_contacts); _print_events(gl_person_data->associated_contacts); return gl_person_data; }
- Get person details.
- Get the display name.
Assuming that you have the person record handle (contacts_record_h), you can access the display_name property. You can read the display name property and print it:
static bool _get_display_name(contacts_record_h record, char **display_name) { int error_code; error_code = contacts_record_get_str(record, _contacts_person.display_name, display_name); dlog_print(DLOG_DEBUG, LOG_TAG, "display name: %s", *display_name); if (error_code != CONTACTS_ERROR_NONE) return false; return true; }
- Get associated contacts.
You can get the associated contacts of a person by query. In this example, you get the associated contact records.
static bool _get_associated_contacts(contacts_record_h record, contacts_list_h *associated_contacts) { int error_code; int person_id; contacts_query_h query = NULL; contacts_filter_h filter = NULL; error_code = contacts_record_get_int(record, _contacts_person.id, &person_id); error_code = CONTACTS_ERROR_NONE; error_code += contacts_query_create(_contacts_contact._uri, &query); error_code += contacts_filter_create(_contacts_contact._uri, &filter); error_code += contacts_filter_add_int(filter, _contacts_contact.person_id, CONTACTS_MATCH_EQUAL, person_id); error_code += contacts_query_set_filter(query, filter); error_code += contacts_db_get_records_with_query(query, 0, 0, associated_contacts); contacts_filter_destroy(filter); contacts_query_destroy(query); if (error_code != CONTACTS_ERROR_NONE) return false; return true; }
- Get phone numbers.
You can get the numbers of a person by iterating the contacts list. In this example, you get all the number records and print them.
static void _print_phone_numbers(contacts_list_h associated_contacts) { int error_code; contacts_record_h contact; if (NULL == associated_contacts) { dlog_print(DLOG_ERROR, LOG_TAG, "associated_contacts is NULL"); return; } while (contacts_list_get_current_record_p(associated_contacts, &contact) == CONTACTS_ERROR_NONE) { int i; unsigned int count = 0; error_code = contacts_record_get_child_record_count(contact, _contacts_contact.number, &count); if (CONTACTS_ERROR_NONE != error_code) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts_record_get_child_record_count(%d)", error_code); return; } for (i = 0; i < count; i++) { contacts_record_h number = NULL; error_code = contacts_record_get_child_record_at_p(contact, _contacts_contact.number, i, &number); if (error_code != CONTACTS_ERROR_NONE) continue; int number_id; contacts_record_get_int(number, _contacts_number.id, &number_id); dlog_print(DLOG_DEBUG, LOG_TAG, "number id: %d", number_id); char *number_str = NULL; contacts_record_get_str_p(number, _contacts_number.number, &number_str); dlog_print(DLOG_DEBUG, LOG_TAG, "number: %s", number_str); } error_code = contacts_list_next(associated_contacts); } }
- Get the default phone number.
If a contact has multiple phone numbers, one of them is defined as the default phone number. A person also has a default phone number. You can get the default phone number of a person by query. The Contact Service provides the _contacts_person_number view for getting the default phone number of a person. In the default phone number record, the is_primary_default property value is true. This example shows how to get the default phone number of a person by query.
static bool _get_default_phone_number(contacts_record_h record, char **default_phone_number) { contacts_query_h query = NULL; contacts_filter_h filter = NULL; contacts_list_h list = NULL; contacts_record_h record_person_number = NULL; int person_id; int error_code = CONTACTS_ERROR_NONE; error_code += contacts_record_get_int(record, _contacts_person.id, &person_id); error_code += contacts_query_create(_contacts_person_number._uri, &query); error_code += contacts_filter_create(_contacts_person_number._uri, &filter); error_code += contacts_filter_add_bool(filter, _contacts_person_number.is_primary_default, true); error_code += contacts_query_set_filter(query, filter); error_code += contacts_db_get_records_with_query(query, 0, 0, &list); error_code += contacts_list_get_current_record_p(list, &record_person_number); error_code += contacts_record_get_str(record_person_number, _contacts_person_number.number, default_phone_number); contacts_list_destroy(list, true); contacts_filter_destroy(filter); contacts_query_destroy(query); if (error_code != CONTACTS_ERROR_NONE) return false; return true; }
- Get events.
You can get the events by iterating the contacts list.
static void _print_events(contacts_list_h associated_contacts) { int error_code; contacts_record_h contact; if (NULL == associated_contacts) { dlog_print(DLOG_ERROR, LOG_TAG, "associated_contacts is NULL"); return; } while (contacts_list_get_current_record_p(associated_contacts, &contact) == CONTACTS_ERROR_NONE) { int i; unsigned int count = 0; error_code = contacts_record_get_child_record_count(contact, _contacts_contact.event, &count); if (CONTACTS_ERROR_NONE != error_code) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts_record_get_child_record_count(%d)", error_code); return; } for (i = 0; i < count; i++) { contacts_record_h event = NULL; error_code = contacts_record_get_child_record_at_p(contact, _contacts_contact.event, i, &event); if (error_code != CONTACTS_ERROR_NONE) continue; int event_id; contacts_record_get_int(event, _contacts_event.id, &event_id); dlog_print(DLOG_DEBUG, LOG_TAG, "event id: %d", event_id); int date; contacts_record_get_int(event, _contacts_event.date, &date); dlog_print(DLOG_DEBUG, LOG_TAG, "event: %d", date); } error_code = contacts_list_next(associated_contacts); } }
- Get the display name.
-
- When you no longer need the person record, destroy the used structures:
contacts_list_destroy(list, true);
-
- To get the filtered person record list:
- Use the contacts_db_get_records_with_query() function to filter the list with parameters:
- To get a person list with filtering, create a record list and a query:
contacts_list_h list = NULL; contacts_query_h query = NULL; error_code = contacts_query_create(_contacts_person._uri, &query);
- Create a filter:
contacts_filter_h filter = NULL; error_code = contacts_filter_create(_contacts_person._uri, &filter);
- Add a condition, such as display_name:
error_code = contacts_filter_add_str(filter, _contacts_person.display_name, CONTACTS_MATCH_CONTAINS, "John");
- To add multiple conditions, you must define an operator between the conditions:
error_code = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND); error_code = contacts_filter_add_bool(filter, _contacts_person.is_favorite, true);
- Connect the query with the list:
error_code = contacts_query_set_filter(query, filter); error_code = contacts_db_get_records_with_query(query, 0, 0, &list);
The third parameter refers to a limit of the results. If 0 is passed, there are no limits. Remember that after all operations, the list must be released.
- Free the filter and query:
contacts_filter_destroy(filter); contacts_query_destroy(query);
- To get a person list with filtering, create a record list and a query:
- Iterate the list and read the records.
- When you no longer need the person record, destroy the used structures:
contacts_list_destroy(list, true);
- Use the contacts_db_get_records_with_query() function to filter the list with parameters:
- To get the searched person record list:
- Use the contacts_db_search_records() function.
The Contact Service provides an API for the contact search. The contacts_db_search_records() function provides an easy way to find records based on a given keyword. The following example shows how to find the contact records which contain the "John" keyword:
contacts_list_h list = NULL; error_code = contacts_db_search_records(_contacts_person._uri, "John", 0, 0, &list);
- Iterate the list and read the records.
- When you no longer need the person record, destroy the used structures:
contacts_list_destroy(list, true);
- Use the contacts_db_search_records() function.
Updating a Contact
To change the name, birthday, and phone number of an existing contact:
- Get the contact.
To modify a record, you need to have a handle (contacts_record_h type variable) to a memory object representing the record in the database. One of the ways to acquire it is to use the contact ID:
int contact_id = ... // Acquire contact ID contacts_record_h contact = NULL; error_code = contacts_db_get_record(_contacts_contact._uri, contact_id, &contact);
Such handles are also provided by search functions, such as contacts_db_get_records_with_query().
- Change the name.
-
To modify the contact name, get the name record with the contacts_record_get_child_record_at_p() function, which provides a list of the child records of a given type.
contacts_record_h name = NULL; error_code = contacts_record_get_child_record_at_p(contact, _contacts_contact.name, 0, &name);
The function parameters are the parent record, the child record type, a child record index, and the resulting child record. Since there can be only one child record of type _contacts_contact.name, the index is set to 0 to get the first (and only) child record.
- Change the first name:
error_code = contacts_record_set_str(name, _contacts_name.first, "Mark");
This only changes the data in the memory object, not in the database. To insert the new value, the name record must be inserted. However, if you acquire this record using contacts_record_get_child_record_at_p() (as in this example), you only need to update the parent record.
-
- Change the birthday event.
- If only 1 event is set for the contact, you can call contacts_record_get_child_record_at_p() to get the event record. If there are more events, you must iterate over the child records.
contacts_record_h event = NULL; error_code = contacts_record_get_child_record_at_p(contact, _contacts_contact.event, 0, &event);
- Update the record:
int new_date = 1990 * 10000 + 6 * 100 + 21; error_code = contacts_record_set_int(event, _contacts_event.date, new_date);
- If only 1 event is set for the contact, you can call contacts_record_get_child_record_at_p() to get the event record. If there are more events, you must iterate over the child records.
- Update the contact record.
Update the contact. Any changes in the child records (such as name and birthday) are also inserted.
error_code = contacts_db_update_record(contact);
- When the record handle is no more needed, use the contacts_record_destroy() function to destroy the record handle and free the allocated memory:
contacts_record_destroy(contact, true);
Deleting a Person
To delete a person, call the contacts_db_delete_record() function with _contacts_person._uri as the first parameter and the person ID as the second one:
int person_id = ... // Acquire person ID error_code = contacts_db_delete_record(_contacts_person._uri, person_id);
Linking and Unlinking Contacts
To link and unlink contacts (manually and automatically):
- To link a person to another person manually, call the contacts_person_link_person() function with base person ID as the first parameter and another person ID as the second one.
int person_id1 = ... // Acquire base person ID int person_id2 = ... // Acquire another person ID error_code = contacts_person_link_person(person_id1, person_id2);
- To link a contact automatically to a person when creating, set the link_mode property to CONTACTS_CONTACT_LINK_MODE_NONE when inserting.
The Contact Service determines the link based on the number and email properties. If the links leads to a contact in the same address book, the link does not work.
contacts_record_h contact = NULL; error_code = CONTACTS_ERROR_NONE; error_code += contacts_record_create(_contacts_contact._uri, &contact); error_code += contacts_record_set_int(contact, _contacts_contact.link_mode, CONTACTS_CONTACT_LINK_MODE_NONE); contacts_record_h name = NULL; error_code += contacts_record_create(_contacts_name._uri, &name); error_code += contacts_record_set_str(name, _contacts_name.first, "John"); error_code += contacts_record_add_child_record(contact, _contacts_contact.name, name); contacts_record_h number = NULL; error_code += contacts_record_create(_contacts_number._uri, &number); error_code += contacts_record_set_str(number, _contacts_number.number, "+8210-1234-5678"); error_code += contacts_record_add_child_record(contact, _contacts_contact.number, number); // Contact is linked automatically if an existing person has the same number in a different address book error_code += contacts_db_insert_record(contact, NULL); contacts_record_destroy(contact, true);
- To unlink a contact from a person, call the contacts_person_unlink_contact() function with the base person ID as the first parameter and the contact ID as the second one. A new person is created when unlinking. You can get the new person ID as the third parameter.
int person_id = ... // Acquire base person ID int contact_id = ... // Acquire contact ID int unlinked_person_id; error_code = contacts_person_unlink_contact(person_id, contact_id, &unlinked_person_id);
Managing Favorites
To manage person favorites:
- To set a person as favorite when creating a contact, use the is_favorite property of the person record. If the property is set to true when creating a contact, the person is set as favorite:
contacts_record_h contact = NULL; error_code = CONTACTS_ERROR_NONE; error_code += contacts_record_create(_contacts_contact._uri, &contact); error_code += contacts_record_set_bool(contact, _contacts_contact.is_favorite, true); // Set other properties // New person is set as favorite error_code += contacts_db_insert_record(contact, NULL); contacts_record_destroy(contact, true);
- To set an existing person as favorite, update the person record:
int person_id = ... // Acquire person ID contacts_record_h person = NULL; error_code = contacts_db_get_record(_contacts_person._uri, person_id, &person); error_code = contacts_record_set_bool(person, _contacts_person.is_favorite, true); error_code = contacts_db_update_record(person); contacts_record_destroy(person, true);
- To unset a favorite:
int person_id = ... // Acquire person ID contacts_record_h person = NULL; error_code = contacts_db_get_record(_contacts_person._uri, person_id, &person); error_code = contacts_record_set_bool(person, _contacts_person.is_favorite, false); error_code = contacts_db_update_record(person); contacts_record_destroy(person, true);
Monitoring Person Changes
To register a callback function to listen for person changes:
- Register the callback function.
error_code = contacts_db_add_changed_cb(_contacts_person._uri, _person_changed_callback, NULL);
- Define the callback function.
The callback function is called when the person data changes. The code below shows how to update person details in the callback function.
static contacts_gl_person_data_t *_gl_person_data = ... void _person_changed_callback(const char *view_uri, void *user_data) { int error_code; if (0 != strcmp(view_uri, _contacts_person._uri)) return; if (_gl_person_data == NULL) return; int person_id = _gl_person_data->id; _free_gl_person_data(_gl_person_data); _gl_person_data = NULL; contacts_record_h record = NULL; error_code = contacts_db_get_record(_contacts_person._uri, person_id, &record); if (error_code != CONTACTS_ERROR_NONE) return; _gl_person_data = _create_gl_person_data(record); // Use _gl_person_data contacts_record_destroy(record, true); }
Creating a Group
To create a new group record:
contacts_record_h group = NULL; error_code = contacts_record_create(_contacts_group._uri, &group);
Setting Group Properties
To set group properties:
- Set the group name.
The contacts_record_set_str() function sets the name of the group when the second argument is _contacts_group.name. This function takes the group record handle as the first argument, and the name, which is a string value, as the third argument. The name argument is taken from the UI part of the application. The function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, and disconnecting from the service if needed.
error_code = contacts_record_set_str(group, _contacts_group.name, "Neighbors");
- Set an image and ringtone path.
You can set the other properties similarly. To set the image and ringtone path, call the contacts_record_set_str() function and check the error codes.
char *resource_path = app_get_resource_path(); char temp_path[1024]; snprintf(temp_path, sizeof(temp_path), "%s/group_image.jpg", resource_path); error_code = contacts_record_set_str(group, _contacts_group.image_path, temp_path); snprintf(temp_path, sizeof(temp_path), "%s/ringtone.mp3", resource_path); free(resource_path); error_code = contacts_record_set_str(group, _contacts_group.ringtone_path, temp_path);
Inserting a Group to the Database
To insert a group record:
- Use the contacts_db_insert_record() function to insert a newly created group into the Contacts database.
The first argument is the group record handle, the second is the record ID. A unique ID is assigned to the record your are adding, and is returned as the third argument of the called function. If the group is inserted successfully, the function returns CONTACTS_ERROR_NONE.
int added_group_id = -1; error_code = contacts_db_insert_record(group, &added_group_id);
- After inserting, the used structures have to be destroyed:
contacts_record_destroy(group, true);
Getting Groups
To get all of the group records one by one, or to filter them by one of the properties:
- To get a single group record:
-
Use the contacts_db_get_record() function with the appropriate group_id:
contacts_record_h group; int group_id = ... // Acquire group ID error_code = contacts_db_get_record(_contacts_group._uri, group_id, &group);
- When you no longer need the group record, destroy the used structures:
contacts_record_destroy(group, true);
-
- To get the total group record list:
-
Use the contacts_db_get_all_records() function:
contacts_list_h list = NULL; error_code = contacts_db_get_all_records(_contacts_group._uri, 0, 0, &list);
- To iterate the list and read the records:
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. -
To get the records from the list, use the contacts_list_get_current_record_p(), and contacts_list_next() or contacts_list_prev() functions. Get the details of each record in the loop.
contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { char* name; error_code = contacts_record_get_str_p(record, _contacts_group.name, &name); dlog_print(DLOG_DEBUG, LOG_TAG, "group name: %s", name); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
- If you want to get more details of each record, use the contacts_gl_group_data_t structure like below:
contacts_gl_group_data_t *gl_group_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_group_data = _create_gl_group_data(record); // You can get, for example, display name: // gl_group_data->name error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
- The memory for the record data is allocated, and the data is copied from the record by the functions listed in the following snippet:
typedef struct _contacts_gl_group_data { int id; char *name; char *image_path; char *ringtone_path; } contacts_gl_group_data_t; static void _free_gl_group_data(contacts_gl_group_data_t *gl_group_data) { if (NULL == gl_group_data) return; free(gl_group_data->name); free(gl_group_data->image_path); free(gl_group_data->ringtone_path); free(gl_group_data); } static contacts_gl_group_data_t* _create_gl_group_data(contacts_record_h record) { contacts_gl_group_data_t *gl_group_data; int error_code; gl_group_data = malloc(sizeof(contacts_gl_group_data_t)); memset(gl_group_data, 0x0, sizeof(contacts_gl_group_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_group.id, &gl_group_data->id)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.name, &gl_group_data->name)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.image_path, &gl_group_data->image_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.ringtone_path, &gl_group_data->ringtone_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } return gl_group_data; }
-
- When you no longer need the group record, destroy the used structures:
contacts_list_destroy(list, true);
-
- To get the filtered group record list:
- Use the contacts_db_get_records_with_query() function to filter the list with parameters:
- To get groups with filtering, you need a record list and a query:
contacts_list_h list = NULL; contacts_query_h query = NULL; error_code = contacts_query_create(_contacts_group._uri, &query);
- Before getting the groups, filter the list. There is a possibility to filter based on various parameters. To create a filter, the following code is used:
contacts_filter_h filter = NULL; error_code = contacts_filter_create(_contacts_group._uri, &filter);
- Add a condition, such as group name:
error_code = contacts_filter_add_str(filter, _contacts_group.name, CONTACTS_MATCH_CONTAINS, "neighbors");
That way only groups which contain the name "neighbors" are retrieved. To use multiple conditions, add an operator between them:
error_code = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR); error_code = contacts_filter_add_str(filter, _contacts_group.name, CONTACTS_MATCH_CONTAINS, "friend");
- Connect the query with the list:
error_code = contacts_query_set_filter(query, filter); error_code = contacts_db_get_records_with_query(query, 0, 0, &list);
The third parameter refers to the limit of the results. If 0 is passed, there are no limits. Remember that after all operations, the list must be released.
- Free the filter and query:
contacts_filter_destroy(filter); contacts_query_destroy(query);
- To get groups with filtering, you need a record list and a query:
- To iterate the list and read the records:
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. -
To get the records from the list, use the contacts_list_get_current_record_p(), and contacts_list_next() or contacts_list_prev() functions. Get the details of each record in the loop.
contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { char* name; error_code = contacts_record_get_str_p(record, _contacts_group.name, &name); dlog_print(DLOG_DEBUG, LOG_TAG, "group name: %s", name); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
-
If you want to get more details of each record, use the contacts_gl_group_data_t structure like below:
contacts_gl_group_data_t *gl_group_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_group_data = _create_gl_group_data(record); // You can get, for example, display name: // gl_group_data->name error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
-
The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
typedef struct _contacts_gl_group_data { int id; char *name; char *image_path; char *ringtone_path; } contacts_gl_group_data_t; static void _free_gl_group_data(contacts_gl_group_data_t *gl_group_data) { if (NULL == gl_group_data) return; free(gl_group_data->name); free(gl_group_data->image_path); free(gl_group_data->ringtone_path); free(gl_group_data); } static contacts_gl_group_data_t* _create_gl_group_data(contacts_record_h record) { contacts_gl_group_data_t *gl_group_data; int error_code; gl_group_data = malloc(sizeof(contacts_gl_group_data_t)); memset(gl_group_data, 0x0, sizeof(contacts_gl_group_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_group.id, &gl_group_data->id)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.name, &gl_group_data->name)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.image_path, &gl_group_data->image_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_group.ringtone_path, &gl_group_data->ringtone_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_group_data(gl_group_data); return NULL; } return gl_group_data; }
-
- When you no longer need the group record, destroy the used structures:
contacts_list_destroy(list, true);
- Use the contacts_db_get_records_with_query() function to filter the list with parameters:
Updating a Group
To change the name and image of an existing person:
- Get the group.
To modify a record, you need to have a handle (contacts_record_h type variable) to a memory object representing the record in the database. One of the ways to acquire it is to use the group ID:
int group_id = ... // Acquire group ID contacts_record_h group = NULL; error_code = contacts_db_get_record(_contacts_group._uri, group_id, &group);
Such handles are also provided by search functions, such as contacts_db_get_records_with_query().
- Change the name and image.
Change the name and image property using the contacts_record_set_str() function.
error_code = contacts_record_set_str(group, _contacts_group.name, "Family"); char *resource_path = app_get_resource_path(); char temp_path[1024]; snprintf(temp_path, sizeof(temp_path), "%s/group_image_new.jpg", resource_path); free(resource_path); error_code = contacts_record_set_str(group, _contacts_group.image_path, temp_path);
- Update the group record.
Update the group. The above changes (name and image) are also inserted.
error_code = contacts_db_update_record(group);
- Clean up.
When the record handle is no longer needed, use the contacts_record_destroy() function to destroy the record handle and free the allocated memory.
contacts_record_destroy(group, true);
Deleting a Group
To delete a group, call the contacts_db_delete_record() function with _contacts_group._uri as the first parameter and group ID as the second one;
int group_id = ... // Acquire group ID error_code = contacts_db_delete_record(_contacts_group._uri, group_id);
Managing Group Members
To manage group members:
- To add a group member, you need to know the contact ID and the group ID. Then you need to call contacts_group_add_contact().
int contact_id = ... // Acquire contact ID int group_id = ... // Acquire group ID error_code = contacts_group_add_contact(group_id, contact_id);
- To remove a contact from a group, call contacts_group_remove_contact().
error_code = contacts_group_remove_contact(group_id, contact_id);
- To get a list of persons assigned to a specific group:
- Get the records of type _contacts_person_group_assigned:
contacts_query_h query = NULL; contacts_filter_h filter = NULL; contacts_list_h list = NULL; contacts_query_create(_contacts_person_group_assigned._uri, &query); contacts_filter_create(_contacts_person_group_assigned._uri, &filter); contacts_filter_add_int(filter, _contacts_person_group_assigned.group_id, CONTACTS_MATCH_EQUAL, group_id); contacts_query_set_filter(query, filter); contacts_db_get_records_with_query(query, 0, 0, &list);
- Iterate over the list elements.
contacts_record_h person = NULL; int error_code; while (contacts_list_get_current_record_p(list, &person) == CONTACTS_ERROR_NONE) { int person_id; contacts_record_get_int(person, _contacts_person_group_assigned.person_id, &person_id); dlog_print(DLOG_DEBUG, LOG_TAG, "Person id: %d", person_id); char *display_name; contacts_record_get_str_p(person, _contacts_person_group_assigned.display_name, &display_name); dlog_print(DLOG_DEBUG, LOG_TAG, "Display name: %s", display_name); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
- Destroy the filter, query, and list handles when no longer needed.
contacts_list_destroy(list, true); contacts_filter_destroy(filter); contacts_query_destroy(query);
- Get the records of type _contacts_person_group_assigned:
Monitoring Group Changes
To register a callback function to listen for group changes:
- Register the callback function.
The code below shows how to register a callback function to listen for group changes.
error_code = contacts_db_add_changed_cb(_contacts_group._uri, _group_changed_callback, NULL);
- Define the callback function.
The callback function is called when the group data changes. The code below shows how to update the group details in the callback function.
static contacts_gl_group_data_t *_gl_group_data = ... static void _group_changed_callback(const char *view_uri, void *user_data) { int error_code; if (0 != strcmp(view_uri, _contacts_group._uri)) return; if (_gl_group_data == NULL) return; int group_id = _gl_group_data->id; _free_gl_group_data(_gl_group_data); _gl_group_data = NULL; contacts_record_h record = NULL; error_code = contacts_db_get_record(_contacts_group._uri, group_id, &record); if (error_code != CONTACTS_ERROR_NONE) return; _gl_group_data = _create_gl_group_data(record); // Use _gl_group_data contacts_record_destroy(record, true); }
Making a vCard
To make a vCard stream from a person record:
- Get the person record by the person ID.
int person_id = ... // Acquire person ID contacts_record_h record = NULL; error_code = contacts_db_get_record(_contacts_person._uri, person_id, &record);
- Make the vCard stream by the person record.
char *vcard_stream = NULL; error_code = contacts_vcard_make_from_person(record, &vcard_stream);
Note The Contact Service API allows you to make a vCard stream from a person, contact, and my profile records: int contacts_vcard_make_from_person(contacts_record_h person, char **vcard_stream); int contacts_vcard_make_from_contact(contacts_record_h contact, char **vcard_stream); int contacts_vcard_make_from_my_profile(contacts_record_h my_profile, char **vcard_stream);
- Destroy the handle when it is no longer needed.
free(vcard_stream); contacts_record_destroy(record, true);
Parsing a vCard
To parse a vCard from a file and insert to the database:
char *resource_path = app_get_resource_path(); char temp_path[1024]; snprintf(temp_path, sizeof(temp_path), "%s/vcard.vcf", resource_path); free(resource_path); error_code = contacts_vcard_parse_to_contact_foreach(temp_path, // File path of vCard _vcard_parse_cb, // Callback function to invoke NULL); // User data to be passed to the callback function
The vCard stream contains multiple contact objects. The callback function is called after parsing each contact. If you return false on the callback function, parsing stops.
static bool _vcard_parse_cb(contacts_record_h contact, void *user_data) { if (NULL == contact) return false; int contact_id = -1; error_code = contacts_db_insert_record(contact, &contact_id); // Use the contact record return true; }
Creating a Speed Dial
To create a speed dial record:
contacts_record_h speeddial; error_code = contacts_record_create(_contacts_speeddial._uri, &speeddial);
The first argument determines the type of the created record. Use _contacts_speeddial._uri to create speed dial type records.
Setting Speed Dial Properties
To set speed dial properties:
- Set the speed dial number.
The contacts_record_set_int() function sets the speed dial type when the second argument is _contacts_speeddial.speeddial_number. This function takes the speed dial record handle as the first argument, and the speed dial number, which is an integer value, as the third argument. The function returns the status code. If the function returns an error, take appropriate action, such as freeing memory, removing handles, or disconnecting from the service.
int speeddial_number = ... // Acquire speed dial number error_code = contacts_record_set_int(speeddial, _contacts_speeddial.speeddial_number, speeddial_number);
- Set the number ID:
int number_id = ... // Acquire number id error_code = contacts_record_set_int(speeddial, _contacts_speeddial. number_id, number_id);
Note |
---|
This tutorial does not describe how to insert a number. For more information, see the Contact Tutorial. |
Inserting a Speed Dial to the Database
To insert a speed dial record:
- Use the contacts_db_insert_record() function to insert a newly created speed dial into the Contacts database. The first argument is the speed dial record handle, the second is the speed dial number. If the speed dial is inserted successfully, the function returns CONTACTS_ERROR_NONE.
int added_speeddial_id = -1; error_code = contacts_db_insert_record(speeddial, &added_speeddial_id);
- After inserting the speed dial record, destroy the used structures:
contacts_record_destroy(speeddial, true);
Getting Speed Dials
To get all of the speed dial records one by one, or to filter them by one of the properties:
- To get a single speed dial record:
-
Use the contacts_db_get_record() function with the appropriate speeddial_id:
contacts_record_h speeddial; int speeddial_id = ... // Acquire speed dial ID error_code = contacts_db_get_record(_contacts_speeddial._uri, speeddial_id, &speeddial);
- After finish using the speed dial record, destroy the used structures:
contacts_record_destroy(speeddial, true);
-
- To get the total speed dial record list:
- Use the contacts_db_get_all_records() function:
contacts_list_h list = NULL; error_code = contacts_db_get_all_records(_contacts_speeddial._uri, 0, 0, &list);
- To iterate the list and read the records, you can get the records from the list using the contacts_list_get_current_record_p(), contacts_list_next(), or contacts_list_prev() function. Get the details of each record in the loop.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { int number; error_code = contacts_record_get_int(record, _contacts_speeddial.speeddial_number, &number); dlog_print(DLOG_DEBUG, LOG_TAG, "speed dial number: %d", number); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
To get more details of each record, use the contacts_gl_speeddial_data_t structure:
contacts_gl_speeddial_data_t *gl_speeddial_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_speeddial_data = _create_gl_speeddial_data(record); _free_gl_speeddial_data(gl_speeddial_data); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
The memory for the record data is allocated, and the data is copied from the record by the functions shown in the following snippet:
typedef struct _contacts_gl_speeddial_data { int speeddial_number; char *number; char *display_name; char *image_thumbnail_path; } contacts_gl_speeddial_data_t; static void _free_gl_speeddial_data(contacts_gl_speeddial_data_t *gl_speeddial_data) { if (NULL == gl_speeddial_data) return; free(gl_speeddial_data->number); free(gl_speeddial_data->display_name); free(gl_speeddial_data->image_thumbnail_path); free(gl_speeddial_data); } static contacts_gl_speeddial_data_t* _create_gl_speeddial_data(contacts_record_h record) { contacts_gl_speeddial_data_t *gl_speeddial_data; int error_code; gl_speeddial_data = malloc(sizeof(contacts_gl_speeddial_data_t)); memset(gl_speeddial_data, 0x0, sizeof(contacts_gl_speeddial_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_speeddial.speeddial_number, &gl_speeddial_data->speeddial_number)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.number, &gl_speeddial_data->number)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.display_name, &gl_speeddial_data->display_name)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.image_thumbnail_path, &gl_speeddial_data->image_thumbnail_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } return gl_speeddial_data; }
- After you no longer need the speed dial record, destroy the used structures:
contacts_list_destroy(list, true);
- Use the contacts_db_get_all_records() function:
- To get the filtered speed dial record list:
- Use the contacts_db_get_records_with_query() function.
- Create a record list and query:
contacts_list_h list = NULL; contacts_query_h query = NULL; error_code = contacts_query_create(_contacts_speeddial._uri, &query);
- Filter the list before getting the speed dials. It is possible to filter with various parameters. To create a filter:
contacts_filter_h filter = NULL; error_code = contacts_filter_create(_contacts_speeddial._uri, &filter);
- Add a condition, such as the speed dial number.
The following example retrieves only those speed dials whose numbers are less than 3.
error_code = contacts_filter_add_int(filter, _contacts_speeddial.speeddial_number, CONTACTS_MATCH_LESS_THAN, 3);
To use multiple conditions, add an operator between them:
error_code = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR); error_code = contacts_filter_add_int(filter, _contacts_speeddial.speeddial_number, CONTACTS_MATCH_GREATER_THAN, 15);
- Connect the query with the list:
error_code = contacts_query_set_filter(query, filter); error_code = contacts_db_get_records_with_query(query, 0, 0, &list);
The third parameter refers to the limit of the results. If 0 is passed, there are no limits. Remember that after all operations, the list must be released.
- Free the filter and query:
contacts_filter_destroy(filter); contacts_query_destroy(query);
- Create a record list and query:
- To iterate the list and read the records, you can get the records from the list using the contacts_list_get_current_record_p(), contacts_list_next(), or contacts_list_prev() function. Get the details of each record in the loop.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { int number; error_code = contacts_record_get_int(record, _contacts_speeddial.speeddial_number, &number); dlog_print(DLOG_DEBUG, LOG_TAG, "speed dial number: %d", number); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
To get more details of each record, use the contacts_gl_speeddial_data_t structure:
contacts_gl_speeddial_data_t *gl_speeddial_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_speeddial_data = _create_gl_speeddial_data(record); _free_gl_speeddial_data(gl_speeddial_data); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
The memory for the record data is allocated, and the data is copied from the record by the functions shown in the following snippet.
typedef struct _contacts_gl_speeddial_data { int speeddial_number; char *number; char *display_name; char *image_thumbnail_path; } contacts_gl_speeddial_data_t; static void _free_gl_speeddial_data(contacts_gl_speeddial_data_t *gl_speeddial_data) { if (NULL == gl_speeddial_data) return; free(gl_speeddial_data->number); free(gl_speeddial_data->display_name); free(gl_speeddial_data->image_thumbnail_path); free(gl_speeddial_data); } static contacts_gl_speeddial_data_t* _create_gl_speeddial_data(contacts_record_h record) { contacts_gl_speeddial_data_t *gl_speeddial_data; int error_code; gl_speeddial_data = malloc(sizeof(contacts_gl_speeddial_data_t)); memset(gl_speeddial_data, 0x0, sizeof(contacts_gl_speeddial_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_speeddial.speeddial_number, &gl_speeddial_data->speeddial_number)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.number, &gl_speeddial_data->number)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.display_name, &gl_speeddial_data->display_name)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_speeddial.image_thumbnail_path, &gl_speeddial_data->image_thumbnail_path)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_speeddial_data(gl_speeddial_data); return NULL; } return gl_speeddial_data; }
- When you no longer need the speed dial record, destroy the used structures:
contacts_list_destroy(list, true);
- Use the contacts_db_get_records_with_query() function.
Updating a Speed Dial
To change the number ID of an existing speed dial:
- Get the speed dial.
To modify a record, you need to have a handle (contacts_record_h type variable) to a memory object representing the record in the database. One of the ways to acquire it is to use the speed dial number:
int speeddial_number = ... // Acquire speed dial number contacts_record_h speeddial = NULL; error_code = contacts_db_get_record(_contacts_speeddial._uri, speeddial_number, &speeddial);
Such handles are also provided by search functions, such as contacts_db_get_records_with_query().
- Change the number ID by setting the number_id property using the contacts_record_set_int() function:
int number_id = ... // Acquire number id error_code = contacts_record_set_int(speeddial, _contacts_speeddial.number_id, number_id); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record set integer failed: %x", error_code);
- Update the speed dial record.
Update the speed dial. The above changes (number_id) are also inserted.
error_code = contacts_db_update_record(speeddial);
- Clean up.
When the record handle is no longer needed, use the contacts_record_destroy() function to destroy the record handle and free the allocated memory.
contacts_record_destroy(speeddial, true);
Deleting a Speed Dial
To delete a speed dial, call the contacts_db_delete_record() function with _contacts_speeddial._uri as the first parameter and speed dial number as the second one;
int speeddial_number = ... // Acquire speed dial number error_code = contacts_db_delete_record(_contacts_speeddial._uri, speeddial_number);
Creating a Log
To create a log record:
contacts_record_h log; error_code = contacts_record_create(_contacts_phone_log._uri, &log); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record create failed: %x", error_code);
The first argument determines the type of the created record. Use _contacts_phone_log._uri to create log type records.
Setting Log Properties
To set log properties:
- Set the log type.
The contacts_record_set_int() function sets the type of the log when the second argument is _contacts_phone_log.log_type. This function takes the log record handle as the first argument, and the type, which is a integer value, as the third argument. The function returns the status code. If the function returns an error, free memory, remove handles, and disconnect from the service, if needed.
error_code = contacts_record_set_int(log, _contacts_phone_log.log_type, CONTACTS_PLOG_TYPE_VOICE_INCOMMING); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record set integer failed: %x", error_code);
The enumeration flag names for the log types are:
CONTACTS_PLOG_TYPE_NONE CONTACTS_PLOG_TYPE_VOICE_INCOMMING CONTACTS_PLOG_TYPE_VOICE_OUTGOING CONTACTS_PLOG_TYPE_VIDEO_INCOMING CONTACTS_PLOG_TYPE_VIDEO_OUTGOING CONTACTS_PLOG_TYPE_VOICE_INCOMMING_UNSEEN CONTACTS_PLOG_TYPE_VOICE_INCOMMING_SEEN CONTACTS_PLOG_TYPE_VIDEO_INCOMING_UNSEEN CONTACTS_PLOG_TYPE_VIDEO_INCOMING_SEEN CONTACTS_PLOG_TYPE_VOICE_REJECT CONTACTS_PLOG_TYPE_VIDEO_REJECT CONTACTS_PLOG_TYPE_VOICE_BLOCKED CONTACTS_PLOG_TYPE_VIDEO_BLOCKED CONTACTS_PLOG_TYPE_MMS_INCOMING CONTACTS_PLOG_TYPE_MMS_OUTGOING CONTACTS_PLOG_TYPE_SMS_INCOMING CONTACTS_PLOG_TYPE_SMS_OUTGOING CONTACTS_PLOG_TYPE_SMS_BLOCKED CONTACTS_PLOG_TYPE_MMS_BLOCKED CONTACTS_PLOG_TYPE_EMAIL_RECEIVED CONTACTS_PLOG_TYPE_EMAIL_SENT
- Set time, duration, and address:
error_code = contacts_record_set_int(log, _contacts_phone_log.log_time, (int)time(NULL)); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record set integer failed: %x", error_code); error_code = contacts_record_set_int(log, _contacts_phone_log.extra_data1, 37); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record set integer failed: %x", error_code); error_code = contacts_record_set_str(log, _contacts_phone_log.address, "+8231-1234-5678"); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts record set string failed: %x", error_code);
Log time means the number of seconds since 1970-01-01 00:00:00 (UTC). The extra_data1 property means the message_id, email_id, or duration (seconds) of a call. The address property means a number or an email.
Inserting a Log to the Database
To insert a log record:
- Use the contacts_db_insert_record() function to insert a newly created log into the Contacts database. The first argument is the log record handle, the second is the record ID. If the log is inserted successfully, the function returns CONTACTS_ERROR_NONE.
int added_log_id = -1; error_code = contacts_db_insert_record(log, &added_log_id); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts db insert record failed: %x", error_code);
- After inserting the log, destroy the used structures:
contacts_record_destroy(log, true);
Getting Logs
To get all log records one by one, or to filter them by one of the properties:
- To get a single log record:
-
Use the contacts_db_get_record() function with the appropriate log_id:
contacts_record_h log; int log_id = ... // Acquire log ID error_code = contacts_db_get_record(_contacts_phone_log._uri, log_id, &log); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts db get record failed: %x", error_code);
- After inserting the log, destroy the used structures:
contacts_record_destroy(log, true);
-
- To get the total log record list:
-
Use the contacts_db_get_all_records() function:
contacts_list_h list = NULL; error_code = contacts_db_get_all_records(_contacts_phone_log._uri, 0, 0, &list); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts db get all records failed: %x", error_code);
- To iterate the list and read the records, you can get the records from the list using the contacts_list_get_current_record_p(), contacts_list_next(), or contacts_list_prev() function. Get the details of each record in the loop.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { int type; error_code = contacts_record_get_int(record, _contacts_phone_log.log_type, &type); dlog_print(DLOG_DEBUG, LOG_TAG, "log type: %d", type); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
To get more details of each record, use the contacts_gl_log_data_t structure:
contacts_gl_log_data_t *gl_log_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_log_data = _create_gl_log_data(record); _free_gl_log_data(gl_log_data); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
typedef struct _contacts_gl_log_data { int id; char *address; int log_type; int log_time; } contacts_gl_log_data_t; static void _free_gl_log_data(contacts_gl_log_data_t *gl_log_data) { if (NULL == gl_log_data) return; free(gl_log_data->address); free(gl_log_data); } static contacts_gl_log_data_t* _create_gl_log_data(contacts_record_h record) { contacts_gl_log_data_t *gl_log_data; int error_code; gl_log_data = malloc(sizeof(contacts_gl_log_data_t)); memset(gl_log_data, 0x0, sizeof(contacts_gl_log_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.id, &gl_log_data->id)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_phone_log.address, &gl_log_data->address)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.log_type, &gl_log_data->log_type)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.log_time, &gl_log_data->log_time)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } return gl_log_data; }
- After getting the log record, destroy the used structures:
contacts_list_destroy(list, true);
-
- To get the filtered log record list:
- Use the contacts_db_get_records_with_query() function.
- Create a record list and query:
contacts_list_h list = NULL; contacts_query_h query = NULL; error_code = contacts_query_create(_contacts_phone_log._uri, &query); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts query create failed: %x", error_code);
- Before getting the logs, filter the list. There is a possibility to filter based on various parameters. To create a filter, use the following code:
contacts_filter_h filter = NULL; error_code = contacts_filter_create(_contacts_phone_log._uri, &filter); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts filter create failed: %x", error_code);
- Add a condition, such as the log type.
The following example retrieves only those logs which type is CONTACTS_PLOG_TYPE_VOICE_INCOMMING.
error_code = contacts_filter_add_int(filter, _contacts_phone_log.log_type, CONTACTS_MATCH_EQUAL, CONTACTS_PLOG_TYPE_VOICE_INCOMMING); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts filter add integer failed: %x", error_code);
To use multiple conditions, add an operator between them:
error_code = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts filter add operator failed: %x", error_code); error_code = contacts_filter_add_int(filter, _contacts_phone_log.log_type, CONTACTS_MATCH_EQUAL, CONTACTS_PLOG_TYPE_VOICE_OUTGOING); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts filter add integer failed: %x", error_code);
- Connect the query with the list:
error_code = contacts_query_set_filter(query, filter); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts query set filter failed: %x", error_code); error_code = contacts_db_get_records_with_query(query, 0, 0, &list); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts db get records with query failed: %x", error_code);
The third parameter refers to the limit of the results. If 0 is passed, there are no limits. After all operations, release the list.
- Free the filter and query:
contacts_filter_destroy(filter); contacts_query_destroy(query);
- Create a record list and query:
- To iterate the list and read the records, use the contacts_list_get_current_record_p(), contacts_list_next(), or contacts_list_prev() function. Get the details of each record in the loop.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to the data in an existing record. contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { int type; error_code = contacts_record_get_int(record, _contacts_phone_log.log_type, &type); dlog_print(DLOG_DEBUG, LOG_TAG, "log type: %d", type); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
To get more details of each record, use the contacts_gl_log_data_t structure:
contacts_gl_log_data_t *gl_log_data = NULL; contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == CONTACTS_ERROR_NONE) { gl_log_data = _create_gl_log_data(record); _free_gl_log_data(gl_log_data); error_code = contacts_list_next(list); if (error_code != CONTACTS_ERROR_NONE) break; }
The memory for the record data is allocated, and the data is copied from the record by the functions listed further on in this document.
typedef struct _contacts_gl_log_data { int id; char *address; int log_type; int log_time; } contacts_gl_log_data_t; static void _free_gl_log_data(contacts_gl_log_data_t *gl_log_data) { if (NULL == gl_log_data) return; free(gl_log_data->address); free(gl_log_data); } static contacts_gl_log_data_t* _create_gl_log_data(contacts_record_h record) { contacts_gl_log_data_t *gl_log_data; int error_code; gl_log_data = malloc(sizeof(contacts_gl_log_data_t)); memset(gl_log_data, 0x0, sizeof(contacts_gl_log_data_t)); if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.id, &gl_log_data->id)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_str(record, _contacts_phone_log.address, &gl_log_data->address)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get string failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.log_type, &gl_log_data->log_type)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } if (CONTACTS_ERROR_NONE != contacts_record_get_int(record, _contacts_phone_log.log_time, &gl_log_data->log_time)) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts record get integer failed "); _free_gl_log_data(gl_log_data); return NULL; } return gl_log_data; }
- After getting the log record, destroy the used structures.
contacts_list_destroy(list, true);
- Use the contacts_db_get_records_with_query() function.
Deleting a Log
To delete a log, use the contacts_db_delete_record() function with _contacts_phone_log._uri as the first parameter and log ID as the second one:
int log_id = ... // Acquire log ID error_code = contacts_db_delete_record(_contacts_phone_log._uri, log_id); if (error_code != CONTACTS_ERROR_NONE) dlog_print(DLOG_ERROR, LOG_TAG, "contacts db delete record failed: %x", error_code);
Inserting New Records
To insert a new record:
- Create a record.
The basic concept in the Contacts API is a record. A record can be a complex set of data, containing other data. For example, an address record can contain the country, region, and street. 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. Effectively, a record can be a node in a tree or a graph of relations between records.
Each record type has a special view structure, which contains identifiers of its properties. For example, the _contacts_contact view describes the properties of the contact record. It contains properties, such as the name, company, and nickname of the contact. A special property in such structures is the URI, which is used to identify the record type. Every view describing a record has this property.
To create a new contact record, create a root record of the _contacts_contact view type:
contacts_record_h hcontact = NULL; error_code = contacts_record_create(_contacts_contact._uri, &hcontact);
Creating a group is similar to creating a record. The only difference is using another view – the group view.
- Set properties.
Set the properties of the newly created record. Almost every property in the contact view is a record itself, so create more records, as needed. The following example shows how to add an address record to a contact.
- Create a new record.
Use the address view because the added record is an address:
contacts_record_h haddress = NULL; contacts_record_create(_contacts_address._uri, &haddress);
- Set the address record properties (parameters available in the current view):
contacts_record_set_str(haddress, _contacts_address.country, "Korea");
- Add the address record to your contact:
contacts_record_add_child_record(hcontact, _contacts_contact.address, haddress
Do not destroy the record handle which is added to another as a child.
- Create a new record.
- Insert records.
After setting properties, insert the root record only to the database. You receive the ID of this record in the database.
int id; error_code = contacts_db_insert_record(hcontact, &id);
- Clean up.
Destroy the record structure.
error_code = contacts_record_destroy(hcontact, true);
Getting Record Details
To find all records and get their details:
- Get a single record.
Get a record handle when you know its ID:
contacts_record_h record; const int ID = 2; contacts_db_get_record(_contacts_contact._uri, ID, &record);
- Get record details.
To get the details, use the contacts_record_get_* function with the record handle. The following example gets the contact display name:
char * d_name; contacts_record_get_str(record, _contacts_contact.display_name, d_name); free(d_name);
- Get child record details.
When using 1 view, you sometimes need details from another view. For example, you get records using the contact view and need to get the first or last name. If you want to get the name, get the record from the name view using the contacts_db_get_child_record_at_p() function:
contacts_record_h child_record; contacts_record_get_child_record_at_p(record, _contacts_contact.name, 0, &child_record); // In the child_record, you have the record form name view char *f_name; contacts_record_get_str(record, _contacts_name.first_name, f_name); free(f_name);
- Get parent record details.
When using the child view, you sometimes need to get details of the parent. For example, you get records using the name view and want to know whether the contact has an email address. To get the parent details, get its ID in almost every view with contact_id. After that, get the parent record:
contacts_record_h parent_record; int parent_id; contacts_record_get_int(record, _contacts_name.contact_id, &parent_id); contacts_db_get_child_record(_contacts_contact._uri, parent_id, &parent_record); // In the parent_record, get bool bool h_email; contacts_record_get_bool(parent_record, _contacts_contact.has_email, &h_email);
- Get details through a structure.
-
For more record details, use a structure to get them.
The memory for the record data is allocated and the data is copied from the record by functions listed in the following step.
gldata = _create_gl_data(record); char * number = gldata->number; typedef struct _contact_gl_data { int id; char *first; char *last; char *number; char *image_path; } contact_gl_data_t; static contact_gl_data_t *_create_gl_data(contacts_record_h r_contact) { contact_gl_data_t *data; data = malloc(sizeof(contact_gl_data_t)); memset(data, 0x0, sizeof(contact_gl_data_t)); if (! _get_contact_id(r_contact, &data->id)) { free(data); return NULL; } if (!_get_contact_number(r_contact, &data->number)) { free(data); return NULL; } if (!_get_contact_first(r_contact, &data->first)) { free(data->number); free(data); return NULL; } if (!_get_contact_last(r_contact, &data->last)) { free(data->number); free(data->first); free(data); return NULL; } if (!_get_contact_image(r_contact, &data->image_path)) { free(data->number); free(data->first); free(data->last); free(data); return NULL; } return data; }
- Retrieve record data into the structure.
Contacts are organized in a parent-child structure. To access specified data from a record, get the child responsible for the requested type using the contacts_record_get_child_record_at_p() function (for the property lists, see View/Property). Do not pass any data returned by a function with the _p suffix to the free() function.
-
To get the name details, get the _contacts_contact.name (representing the child) from the r_contact parent. Both structures have the contacts_record_h type. After obtaining a child record, get the desired data from it using the contacts_record_get_str() function.
static bool _get_contact_last(contacts_record_h r_contact, char **last) { contacts_record_h r_name; int error_code; error_code = contacts_record_get_child_record_at_p(r_contact, _contacts_contact.name, 0, &r_name); error_code = contacts_record_get_str(r_name, _contacts_name.last, last); }
-
The record ID is obtained directly from the parent record. An ID is a unique number representing the record key in the database. You can manipulate a record with functions, such as contacts_db_get_record() or contacts_db_delete_records(), if you know their ID.
static bool _get_contact_id(contacts_record_h r_contact, int *id) { int error_code; error_code = contacts_record_get_int(r_contact, _contacts_contact.id, id); return true; }
-
To get a contact number, check whether it exists using the contacts_record_get_bool() function. If it exists, use the various Query and Filter functions from the Contacts API to make a query to get a list. At the end, free any data returned by a function not containing the _p suffix.
- Get a list of all numbers and filter the list to get the default:
static bool _get_contact_number(contacts_record_h r_contact, char **number) { int id; int error_code; contacts_record_h r_number; contacts_query_h query = NULL; contacts_filter_h filter = NULL; contacts_list_h list = NULL; if (!_get_contact_id(r_contact, &id)) return false; bool has_number; error_code = contacts_record_get_bool(r_contact, _contacts_contact.has_phonenumber, &has_number); error_code = contacts_query_create(_contacts_number._uri, &query); unsigned int fields[] = { _contacts_number.number }; error_code = contacts_query_set_projection(query, fields, 1); error_code = contacts_filter_create(_contacts_number._uri, &filter); error_code = contacts_filter_add_int(filter, _contacts_number.contact_id, CONTACTS_MATCH_EXACTLY, id); error_code = contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND); error_code = contacts_filter_add_bool(filter, _contacts_number.is_default, true); error_code = contacts_query_set_filter(query, filter); error_code = contacts_db_get_records_with_query(query, 0, 1, &list); error_code = contacts_list_get_current_record_p(list, &r_number); error_code = contacts_record_get_str(r_number, _contacts_number.number, number); contacts_query_destroy(query); contacts_filter_destroy(filter); contacts_list_destroy(list, true); }
-
Directly access the default number:
static bool _get_contact_number(contacts_record_h r_contact, char **number) { int error_code; contacts_record_h r_number; bool has_number; error_code = contacts_record_get_bool(r_contact, _contacts_contact.has_phonenumber, &has_number); if (!has_number) { *number = NULL; return true; } error_code = contacts_record_get_child_record_at_p(r_contact, _contacts_contact.number, 0, &r_number); error_code = contacts_record_get_str(r_number, _contacts_number.number, number); return true; }
To get a second number, change the third parameter (contacts_record_get_child_record_at_p) from 0 to 1.
- Get a list of all numbers and filter the list to get the default:
-
An image can be obtained directly from the parent record:
static bool _get_contact_image(contacts_record_h r_contact, char **image_path) { int error_code; error_code = contacts_record_get_str(r_contact, _contacts_contact.image_thumbnail_path, image_path); dlog_print(DLOG_ERROR, LOG_TAG, "Thumb path: \'%s\'", *image_path); return true; }
-
Get the first name as the last name:
static bool _get_contact_first(contacts_record_h r_contact, char **first) { contacts_record_h r_name; int error_code; error_code = contacts_record_get_child_record_at_p(r_contact, _contacts_contact.name, 0, &r_name); error_code = contacts_record_get_str(r_name, _contacts_name.first, first); }
-
-
- Clean up.
-
Destroy the contacts_list_h list.
When the access to the database is no longer needed, disconnect from the service using the contact_disconnect() function.
error_code = contacts_list_destroy(list, true); error_code = contacts_disconnect();
-
Destroy all other used handles as well:
contacts_query_destroy(query); // If query has been used contacts_filter_destroy(filter); // If filter has been used
-
Handling Lists
To access multiple records using lists and contact property filters, and to sort records:
- Get a record list.
- To get all records:
The following function retrieves all records and returns the result list. After all operations, the list must be released with the contacts_list_destroy() function.
contacts_list_h list = NULL; contacts_db_get_all_records(_contacts_contact._uri, 0, 0, &list);
- To filter and get specific records:
- Create a query for a list.
To filter or sort records, you need a record list and query:
contacts_list_h list = NULL; contacts_query_h query = NULL; contacts_query_create(_contacts_name._uri, &query);
- Create a filter for the query.
Before getting contacts, filter the list. It is possible to filter by various parameters, such as the name view.
contacts_filter_h filter = NULL; contacts_filter_create (_contacts_name._uri, &filter);
The first parameter defines in which view to place the filter. To filter by the first and last name, use the _contacts_name filter. The first parameter of the contacts_query_create() function must be the same parameter as in the filter to be appended. For more information on views, see the View/Property tables.
-
Add a condition, such as the following where only contacts beginning with "Za" are shown:
contacts_filter_add_str(filter, _contacts_name.last_name, CONTACTS_MATCH_CONTAINS, "Za");
To receive contacts which starts by a given string, the CONTACTS_MATCH_CONTAINS parameter has to be set. Use the parameter if you need to get records which contain the given string anywhere.
-
To add more conditions, add operators between them. In this case, define the operator between conditions first:
contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND);
After that you can add another condition. If you need to use a logic expression "C1 AND (C2 OR C3)", conditions 2 and 3 must be in another filter to have logical brackets. The following example shows a filter that passes through contacts with a first name starting with "Ada" or "Igo":
contacts_filter_h n_filter = NULL; contacts_filter_create (_contacts_name._uri, &n_filter); contacts_filter_add_str(n_filter, _contacts_name.first_name, CONTACTS_MATCH_STARTSWITH, "Ada"); contacts_filter_add_operator(n_filter, CONTACTS_FILTER_OPERATOR_OR); contacts_filter_add_str(n_filter, _contacts_name.first_name, CONTACTS_MATCH_STARTSWITH, "Igo”");
-
To add an extra filter to a parent filter:
contacts_filter_add_filter(filter, n_filter);
The parent filter passes through contacts with a last name beginning with "Za" and a first name starting with "Ada" or "Igo".
-
Connect a filter with query:
contacts_query_set_filter(query, filter);
- Create a query for a list.
- To get all records:
- Sort a record list.
To sort records by any of its view details:
contacts_query_set_sort(query, _contacts_name.first, true);
The first parameter is the query to be filtered, the second is the property to sort, and the last sets the ascending order.
- Set a projection to a list.
A projection allows you to query the data for specific properties of a record. It can reduce latency in case of a large database.
To set the projection, use the contacts_query_set_projection() function. The following example limits the properties from the previous steps to the first and last name:
unsigned my_projection[] = {_contacts_name.contact_id, _contacts_name.first, _contacts_name.last} contacts_query_set_projection(query, my_projection, sizeof(my_projection)/sizeof(int));
After filtering, such as getting numbers, there can be several records which differ only in a few detail types. When setting the projection, the results can contain identical records. To avoid these situations, use the distinction function:
contacts_query_set_distinct(query, true);
- Get the record list with a query.
Get the list with the query:
contacts_db_get_records_with_query(query, 0, 0, &list);
The third parameter refers to limiting results. If 0 is passed, there are no limits. Release the list after all the operations.
- Iterate on the list and read the records.
The contacts_list_get_current_record_p() function retrieves a record from the contacts list. The current default record is the first record.
To iterate on a list, use the contacts_list_prev(), contacts_list_next(), contacts_list_first(), and contacts_list_last() functions.
Note Some functions have the _p postfix. It means that the returned value must not be freed by the application, as it is a pointer to data in an existing record. To read records:
- To get only a few details:
contacts_record_h record; while (contacts_list_get_current_record_p(list, &record) == 0) { // Get details char * disp_name; contacts_record_get_str(record, _contacts_contact.display_name, &disp_name); free(disp_name); error_code = contacts_list_next(list); }
-
To get more details, use the following example, where the obtained records are passed to the _create_gl_data() function for further processing:
contacts_record_h record; contact_gl_data_t *gldata = NULL; while (contacts_list_get_current_record_p(list, &record) == 0) { gldata = _create_gl_data(record); error_code = contacts_list_next(list); }
-
The previous examples work if you use the default (_contacts_contact) view. If you use filtering in another view as shown in the filter example, and you want to use this structure (change view to default), use the following code:
contacts_record_h record; contact_gl_data_t *gldata = NULL; while (contacts_list_get_current_record_p(list, &record) == 0) { int record_id; contacts_record_h c_record; contacts_record_get_int(record, _contacts_name._uri, &contact_id); contacts_db_get_record(_contacts_contact._uri, contact_id, &c_record); gldata = _create_gl_data(c_record); error_code = contacts_list_next(list); }
This way it is possible to switch to the default view from another view (in a similar manner to the above example _contacts_name).
- To get only a few details:
- Insert the list to the database.
You can insert a whole list to the database. This can be useful when you have several records to create and you want to insert them all at once.
- If you have a list, use it or create a new one:
contacts_list_h list; contacts_list_create(&list);
- Add records to the list:
contacts_list_add (list, record);
- Insert the list into the database:
int *ids = NULL; unsigned int count = 0; contacts_db_insert_records(list, &ids, &count); dlog_print(DLOG_DEBUG, LOG_TAG, "%d records inserted", count); free(ids);
This inserts the entire list to the database and gets the IDs of the inserted records.
- Destroy the list:
contacts_list_destroy(list, true);
- If you have a list, use it or create a new one:
Deleting Records
To delete records from the contact database, you need to know their ID:
int id; // Get id int error = contacts_db_delete_record(_contacts_contact._uri, id);
If you only have the record handle, get the ID first:
contacts_record_get_int(record, _contacts_contact.id, &id);
Linking Persons
To link persons (a useful joining method if there are several contacts assigned to one person):
- Link a person to another person.
To link persons with the contacts_person_link_person() function, you need the person ID. To get the person ID, use the contacts_record_get_int() function.
int first_person_id; contacts_record h record1; // Get the first record int error_code = contacts_record_get_int(record1, _contacts_contact.person_id, &first_person_id); contacts_record h record2; // Get the second record error_code = contacts_record_get_int(record2, _contacts_contact.person_id, &second_person_id); contacts_person_link_person(first_person_id, second_person_id);
This links the 2 contacts available through record handles.
- Set the default properties.
Set the default values from one of the linked contacts with the contacts_person_set_default_property() function. The first parameter determines the detail to be set using the contacts_person_property_e enum.
To set a default number from one of the persons, you have to know its ID. Get the detail ID using the contacts_record_get_child_record_at_p() function, because you need to get the value from the _contact_number view.
contacts_record_h record; int record_number = -1; // Get the record handle contacts_record_h record_number; error_code = contacts_record_get_child_record_at_p(record, _contacts_contact.number, 0, &record_number); error_code = contacts_record_get_int(record_number, _contacts_number.id, &number_id); error_code = contacts_record_destroy(record_number, true); // Use the record_number variable error_code = contacts_person_set_default_property(CONTACTS_PERSON_PROPERTY_NUMBER, person_id, number_id);
- Get default properties.
Get the default property values of a person with the contacts_person_get_default_property() function:
-
Get the ID of the default email details:
int person_email_number; error_code = contacts_person_get_default_property (CONTACTS_PERSON_PROPERTY_EMAIL, person_id, &person_email_number);
-
Get the default email:
int person_email_detail_number; error_code = contacts_person_get_default_property (CONTACTS_PERSON_PROPERTY_EMAIL, person_id, &person_email_number); contacts_record_h email_record; error_code = contacts_db_get_record(_contacts_email._uri, person_email_detail_number, &email_record); char * default_email; error_code = contacts_record_get_str_p(email_record, _contacts_email.email, &default_email); // Use default_email error_code = contacts_record_destroy(email_record, true);
-
- Unlink persons.
To unlink a contact using the contacts_person_unlink_contact() function:
-
If you have the record handle, get the contact ID:
int person_id; contacts_record_get_int(record, _contacts_contact.id, &person_id);
-
Unlink a contact from another and get its ID:
int unlinked_person_id; int contacts_person_unlink_contact(person_id, contact_id, &unlinked_person_id)
-
Managing Contact Settings
To manage the display settings of contacts:
- Get the display and sorting order.
Check the current display order (the order in which the names are displayed) using the contacts_setting_get_name_display_order() function, and the sorting order using the contacts_setting_get_name_sorting_order() function:
contacts_name_display_order_e display_order; contacts_setting_get_name_display_order (&display_order); // Now you have the display order sprintf("Display order: %s", display_order==CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST?"CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST":"CONTACTS_NAME_DISPLAY_ORDER_LASTFIRST"); contacts_name_sorting_order_e sorting_order; contacts_setting_get_name_sorting_order (&sorting_order); // Now you have the sorting order sprintf("Sorting order: %s", sorting_order==CONTACTS_NAME_SORTING_ORDER_FIRSTLAST?"CONTACTS_NAME_SORTING_ORDER_FIRSTLAST":"CONTACTS_NAME_SORTING_ORDER_LASTFIRST");
- Change the display and sorting orders.
To change the display and sorting orders, use the contacts_setting_set_name_display_order() and contacts_setting_set_name_sorting_order() functions:
contacts_setting_set_name_display_order (CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST); contacts_setting_set_name_sorting_order (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST);
- Track the order changes with callbacks.
To track changes in the display and sorting orders:
- Register callbacks with the contacts_setting_add_name_display_order_changed_cb() and contacts_setting_add_name_sorting_order_changed_cb() functions.
- Define the callbacks themselves:
static void display_changed_cb(contacts_name_display_order_e name_display_order, void *user_data) { dlog_print(DLOG_DEBUG, LOG_TAG, "changed display order: %s", name_display_order==CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST?"CONTACTS_NAME_DISPLAY_ORDER_FIRSTLAST":"CONTACTS_NAME_DISPLAY_ORDER_LASTFIRST"); } static void sorting_changed_cb(contacts_name_sorting_order_e name_display_order, void *user_data) { dlog_print(DLOG_DEBUG, LOG_TAG, "changed sorting order: %s", name_display_order==CONTACTS_NAME_SORTING_ORDER_FIRSTLAST?"CONTACTS_NAME_SORTING_ORDER_FIRSTLAST":"CONTACTS_NAME_SORTING_ORDER_LASTFIRST"); }
The above examples cause a message to be printed when the order changes. To track the changes, write a timeout function after setting the callback.
- Unregister the callbacks when they are no longer needed using the contacts_setting_remove_name_display_order_changed_cb() and contacts_setting_remove_name_sorting_order_changed_cb() functions.
Managing Contacts on the SIM Card
To check whether the SIM card is initialized and then import contacts from the SIM card:
- Check whether the SIM card is initialized.
Before using any SIM card methods, ensure that the SIM card initialization is complete:
bool completed = false; contacts_sim_get_initialization_status(&completed); dlog_print(DLOG_DEBUG, LOG_TAG, "SIM %s completed", completed?"":"not ");
- Import all contacts from the SIM card.
When the contacts from the SIM card are available, import them:
int err = contacts_sim_import_all_contacts();
Importing from vCard
To import contacts from all vCard files from a specified directory:
- Get contact records from a stream.
To receive a records list from the vCard stream, use the contacts_vcard_parse_to_contacts() function. Afterwards, the received list is ready to use and you can perform the iteration on the list.
The following example uses the stream in the vCard format and gets the records from the received list:
char * vcard_stream; // Get vCard stream contacts_list_h contacts_list; int err = contacts_vcard_parse_to_contacts(vcard_stream, contacts_list); while (contacts_list_get_current_record_p(list_import, &record) == 0) { // Get next records from file err = contacts_list_next(list_import); } err = contacts_list_destroy(list_import, true);
You can also use the contacts_vcard_parse_to_contact_foreach() function. With this function, you have to get the file content manually, and it needs a callback:
bool contacts_vcard_cb(contacts_record_h record, void *user_data) { // Here you have a record return true; }
The callback is called for each record from a vCard file. The iteration continues as long as the callback returns true.
To check how many records are contained in a vCard file, use the contacts_vcard_get_entity_count() function.
- Import the vCard stream.
-
Get all the files with a .vcf extension from the directory. It can be done through dirent structures available in the <dirent.h> header. The following example gets the path to every file in a directory:
int internal_storage_id; char *vcf_path = NULL; static bool storage_cb(int storage_id, storage_type_e type, storage_state_e state, const char *path, void *user_data) { if (type == STORAGE_TYPE_INTERNAL) { internal_storage_id = storage_id; return false; } return true; } void _get_storage_path() { int error_code = 0; char *path = NULL; error_code = storage_foreach_device_supported(storage_cb, NULL); error_code = storage_get_directory(internal_storage_id, STORAGE_DIRECTORY_DOWNLOADS, &path); if (error_code != STORAGE_ERROR_NONE) { vcf_path = strdup(path); free(path); } } void _import_vcard() { int path_len = 0; DIR *dir = opendir(vcf_path); struct dirent *pDirent = NULL; if (NULL == dir) { free(vcf_path); return; } while ((pDirent = readdir(dir)) != NULL) { if (pDirent->d_type != DT_REG) continue; char *extension = strrchr(pDirent->d_name, '.'); if (!extension || strcmp(extension, ".vcf")) continue; char * filepath = malloc(strlen(vcf_path)+strlen(pDirent->d_name)+4); sprintf(filepath, "%s/%s", vcf_path, pDirent->d_name); // Full path to file available through filepath string free(filepath); } }
-
If you use the contacts_vcard_parse_to_contacts() function, you need to get the file stream manually. The following example shows how to get a records list from a file:
FILE *fp = fopen(filepath, "r"); fseek(fp, 0, 2); int bufsize = ftell(fp); rewind(fp); if (bufsize < 1) return 1; char * vcard_stream = malloc(sizeof(char) * (bufsize)); memset(vcard_stream, '\0', sizeof(vcard_stream)); if (fp != NULL) { char str[200]; while(fgets(str, 200, fp) != NULL) sprintf(vcard_stream+strlen(vcard_stream), "%s", str); fclose(fp); } else // Error handling int err = contacts_vcard_parse_to_contacts(vcard_stream, contacts_list); free(vcard_stream);
-
You can also use the contacts_vcard_parse_to_contact_foreach() function. It requires a callback and retrieves the file path instead of a file stream:
bool contacts_vcard_cb(contacts_record_h record, void *user_data) { // Here you have a record return true; } err = contacts_vcard_parse_to_contact_foreach (filepath, contacts_vcard_cb, NULL);
-
Add a record in a callback function:
int id = -1; err = contacts_db_insert_record(record, &id);
The following example represents the full code of the previous step:
char []folder = "/path/"; contacts_list_h list_import; contacts_record_h record; err = contacts_vcard_parse_to_contacts(content, &list_import); while (contacts_list_get_current_record_p(list_import, &record) == 0) { int id = -1; err = contacts_db_insert_record(record, &id); // Add to list contacts_list_next(list_import); } DIR *dir = opendir(folder); struct dirent *pDirent = NULL; if (dir) { while ((pDirent = readdir(dir)) != NULL) { if (pDirent->d_type != DT_REG) continue; char *exte = strrchr(pDirent->d_name, '.'); if (!exte || strcmp(exte, ".vcf")) continue; dlog_print(DLOG_DEBUG, LOG_TAG, "file %s", pDirent->d_name); char * file_path = malloc(strlen(folder)+strlen(pDirent->d_name)+4); sprintf(file_path, "%s/%s", folder, pDirent->d_name); int count; contacts_vcard_get_entity_count(file_path, &count); // Number of records in file: count if (count < 1) continue; FILE * fp = fopen(file_path, "r"); if (fseek(fp, 0, 2) != 0) // Error handling int bufsize = ftell(fp); rewind(fp); dlog_print(DLOG_DEBUG, LOG_TAG, "file size: %i", bufsize); if (bufsize < 1) return 1; char * vcard_stream = malloc(sizeof(char) * (bufsize)); memset(vcard_stream, '\0', sizeof(vcard_stream)); if (fp != NULL) { char str[150]; while(fgets(str, 150, fp) != NULL) sprintf(vcard_stream+strlen(vcard_stream), "%s", str); fclose(fp); } else return 1; // Import the contacts contacts_list_h list_import; err = contacts_vcard_parse_to_contacts(vcard_stream, &list_import); if (err != 0) dlog_print(DLOG_ERROR, LOG_TAG, "contacts_vcard_parse_to_contacts failed: %d", err); free(vcard_stream); while (contacts_list_get_current_record_p(list_import, &record) == 0) { int id = -1; err = contacts_db_insert_record(record, &id); // Add to list if (err != 0) dlog_print(DLOG_ERROR, LOG_TAG, "contacts_list_add failed"); err = contacts_list_next(list_import); } err = contacts_list_destroy(list_import, true); if (err != 0) { dlog_print(DLOG_ERROR, LOG_TAG, "contacts_list_destroy failed: %d", err); } free (file_path); } closedir(dir); }
-
Exporting to vCard
To export your contacts to a vCard file:
- Export contacts to a file.
To export a contact from the _contacts_contact view to the vCard format, use the contacts_vcard_make_from_contact() function.
To export details from the _contacts_person view, use the contacts_vcard_make_from_person() function. If you need to export details from the _contacts_my_profile view, use the contacts_vcard_make_from_my_profile() function.
The following example uses the _contacts_contact view, but the use of the other views is the same:
contacts_record_h contact; // Get record to contacts_record_h char *vcard_stream; int err = contacts_vcard_make_from_contact(contact, &vcard_stream); // Stream in vCard format is now in vcard_stream free(vcard_stream);
-
Write to a file:
FILE * file = fopen("/path/contacts.vcf", "w"); fwrite(vcard_stream, 1, strlen(vcard_stream), file); fclose(file);
The following example shows how to get all records from a database and put them into a single file.
Get the list of all records using the contacts_db_get_all_records() function and the current records using the contacts_list_get_current_record_p() function. Get the vCard stream and write to the file in a while loop:
char file_path[] = "/path/contacts.vcf"; contacts_list_h list = NULL; err = contacts_db_get_all_records(_contacts_contact._uri, 0, 0, &list); contacts_record_h record; FILE * file = fopen(file_path, "w"); while (contacts_list_get_current_record_p(list, &record) == 0) { err = contacts_vcard_make_from_contact(record, &vcard_stream); // Save to file fwrite(vcard_stream, 1, strlen(vcard_stream), file); free(vcard_stream); err = contacts_list_next(list); } fclose(file); contacts_list_destroy(list, true);