Copyright © 2010 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
This specification defines an API that provides access to a user's unified address book.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document represents the early consensus of the group on the scope and features of the proposed Contacts API. Issues and editors note in the document highlight some of the points on which the group is still working and would particularly like to get feedback.
This document was published by the Device APIs and Policy Working Group as a First Public Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-device-apis@w3.org (subscribe, archives). All feedback is welcome.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
ServiceContacts
interfaceContacts
interfaceContact
interfaceContactProperties
interfaceContactField
interfaceContactAddress
interfaceContactOptions
interfaceContactFindSuccessCB
interfaceContactSuccessCB
interfaceContactErrorCB
interfaceContactError
interfaceAs well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
The key words must, must not, required, should, should not, recommended, may, and optional in this specification are to be interpreted as described in [RFC2119].
This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains.
This section is non-normative.
The Contacts API defines a high-level interface to provide access to the user's unified contact information, such as names, addresses and other contact information.
The API itself is agnostic of any underlying address book sources and data formats.
The following code extracts illustrate how to search, add, remove and update contact information in a given address book:
Searching for matching contacts.
function successContactFindCallback(contacts) { // do something with resulting contact objects // for (var i in contacts) alert(contacts[i].name); // ... } function generalErrorCB(error) { // do something with resulting errors // alert(error.code); // ... } // Perform an address book search navigator.service.contacts.find( {name: 'Bob'}, successContactFindCallback, generalErrorCB );
Creating a new contact.
// previous example follow-on... // Create new contact var myContact = navigator.service.contacts.create({name: 'Mr. Robert Smith Jr'}); // Add additional contact attributes as required... // myContact.nicknames.push('bobby');
Adding a new contact.
// previous example follow-on... function successContactCallback(contact) { // do something with resulting contact object // alert(contact.name); // ... } // Add new contact myContact.save(successContactCallback, generalErrorCB);
Editing an existing contact.
// previous example follow-on... // e.g. add a new phone number myContact.phones.push({types: ['home'], value: '+440000000002'}); // Update existing contact myContact.save(successContactCallback, generalErrorCB);
Removing an existing contact.
// previous example follow-on... // Remove existing contact myContact.remove(successContactCallback, generalErrorCB);
This section is under development.
This section has been inspired (verbatim where necessary) from the Geolocation WG latest public working draft specification.
There are a number of reasons for this approach:
1. The programmatic styles of the Contacts API and Geolocation API are very similar and because they both have the the same implied user experience within
the same implied User Agent the general security and privacy considerations of both APIs should remain common.
2. The ability to align the security and privacy considerations of the Geolocation API with DAP APIs is important for the potential future benefit
of making any security and privacy mechanisms developed within the DAP WG applicable to the Geolocation API at some point in its own ongoing development.
The API defined in this specification can be used to create, retrieve, update and remove contact information from a user's address books. All API methods disclose information related to a user's contacts such as their phone number(s), email address(es) and other personally identifying information. The distribution of this information could potentially compromise the user's privacy. A conforming implementation of this specification must provide a mechanism that protects the user's privacy and this mechanism should ensure that no contact information is creatable, retrivable, updateable or removable without the user's express permission.
A user agent must not create, retrieve, update or delete contact information to Web sites without the express permission of the user. A user agent must acquire permission through a user interface, unless they have prearranged trust relationships with users, as described below. The user interface must include the URI of the document origin, as defined in [HTML5]. Those permissions that are acquired through the user interface and that are preserved beyond the current browsing session (i.e. beyond the time when the browsing context, as defined in [HTML5], is navigated to another URL) must be revocable and a user agent must respect revoked permissions.
Obtaining the user's express permission to access one API method does not imply the user has granted permission for the same Web site to access other methods provided by this API, or to access the same method with a different set of arguments, as part of the same permission context. If a user has expressed permission for an implementation to, e.g. find a set of existing contacts, the implementation must seek the user's express permission if and when any additional create, find, update or remove function is called on this API.
A user agent may have prearranged trust relationships that do not require such user interfaces. For example, while a Web browser will present a user interface when a Web site performs an address book request, a Widget Runtime may have a prearranged, delegated security relationship with the user and, as such, a suitable alternative security and privacy mechanism with which to authorize the creation, retrieval, update and/or removal of contact information.
Recipients must only request contact information when necessary. Recipients must only use the contact information for the task for which it was provided to them. Recipients must dispose of contact information once that task is completed, unless expressly permitted to retain it by the user. Recipients must also take measures to protect this information against unauthorized access. If contact information is stored, users should be allowed to update and delete this information.
The recipient of contact information must not retransmit the contact information without the user’s express permission. Care should be taken when retransmitting and use of encryption is encouraged.
Recipients must clearly and conspicuously disclose the fact that they are collecting contact data, the purpose for the collection, how long the data is retained, how the data is secured, how the data is shared if it is shared, how users can access, update and delete the data, and any other choices that users have with respect to the data. This disclosure must include an explanation of any exceptions to the guidelines listed above.
This section is non-normative.
Further to the requirements listed in the previous section, implementors of the Contacts API are also advised to consider the following aspects that can negatively affect the privacy of their users: in certain cases, users can inadvertently grant permission to the User Agent to disclose their contacts to Web sites. In other cases, the content hosted at a certain URL changes in such a way that the previously granted contact permissions no longer apply as far as the user is concerned. Or the users might simply change their minds.
Predicting or preventing these situations is inherently difficult. Mitigation and in-depth defensive measures are an implementation responsibility and not prescribed by this specification. However, in designing these measures, implementers are advised to enable user awareness of contact sharing, and to provide easy access to interfaces that enable revocation of permissions.
ServiceContacts
interfaceThe actual object of which the API will be hanging off is still under discussion (e.g. navigator.service
vs from navigator.device
); see ISSUE-67
The ServiceContacts
interface is exposed on the navigator.service
object, as defined in [CORE-DEVICE].
Service implements ServiceContacts
;
All instances of the Service
type are defined to also implement the ServiceContacts
interface.
[NoInterfaceObject]
interface ServiceContacts {
readonly attribute Contacts
contacts;
};
contacts
of type Contacts
, readonlyContacts
interface
The Contacts
interface exposes a database collecting contacts information, such that they may be created, found,
read, updated, and deleted.
Multiple address books, taken
from different sources, can be represented within this unified address book interface. Contacts from different sources can be distinguished using the serviceId
field.. In addition, multiple address books can be displayed by filtering
on the required serviceId
value via the Contacts
find() function.
Equally, multiple contact groups can be represented within this unified address book by specifying a consistent categories
value(s) as part of individual Contact
objects. Multiple contact groups can be displayed by filtering
on the required categories
value(s) via the Contacts
find() function.
[NoInterfaceObject]
interface Contacts {
Contact
create (in ContactProperties
attributes);
PendingOp find (in ContactProperties
filter, in ContactFindSuccessCB
successCB, in optional ContactErrorCB
? errorCB, in optional ContactOptions
options);
};
create
Contact
object.
This method takes one argument. When called, it returns
a Contact
object.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
attributes |
| ✘ | ✘ | The attributes to assign to the resulting object. |
Contact
find
Find contacts in the address book based on a ContactProperties
object acting as a filter.
This method takes two, three or four arguments. When called, it immediately returns
a PendingOp
object , as defined in [CORE-DEVICE], and then asynchronously starts a find contacts process defined as follows:
successCB
.
If the attempt fails, and the method was invoked with a non-null
errorCB
argument, this method must
invoke the errorCB
with a ContactError
object as an argument.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
filter |
| ✘ | ✘ | The filter used in order to select which contacts are returned. |
successCB |
| ✘ | ✘ | Function to call when the asynchronous operation completes |
errorCB |
| ✔ | ✔ | Function to call when the asynchronous operation fails. |
options |
| ✘ | ✔ | The options to apply to the output of this method. |
PendingOp
Contact
interfaceThe Contact
interface captures a single contact item. This interface extends ContactProperties
attributes.
All Contact
objects must include all attributes supported by the implementation, regardless of whether these attributes have been assigned a non-null
value or a null
value. If a supported attribute
has not been assigned a value by the user and/or implementation, then this attribute must still be present in the resulting Contact
object and must have a value of null
.
Each resulting Contact
object must include a non-null
name
attribute.
All other attributes may be optionally assigned a value by the user and/or implementation.
[NoInterfaceObject]
interface Contact : ContactProperties
{
readonly attribute DOMString id;
Contact
clone ();
PendingOp save (in ContactSuccessCB
successCB, in optional ContactErrorCB
? errorCB);
PendingOp remove (in ContactSuccessCB
successCB, in optional ContactErrorCB
? errorCB);
};
id
of type DOMString, readonlyPerhaps we don't want to recommend the use of UUID URN here. Saying that id must be globally unique could suffice, and there may be good reasons why someone would want to use something else (e.g. a SHA mailbox as in FOAF).
A globally unique identifier for the given Contact
object. Each Contact
referenced from Contacts
must include a non-empty id
value.
An implementation must maintain this globally unique resource identifier when a Contact is added to, or present within, an Address Book.
An implementation may use an IANA registered identifier format. The value can also be a non-standard format.
It is recommended that an implementation assign the id attribute as a UUID URN as defined in [RFC4122].
{id: 'urn:uuid:d13d4fd0-4ce9-1cef-b1f2-10a9c1446bf0'}
clone
Create a deep clone copy of the current object minus the current object's id
attribute.
The resulting object must be provided with a newly generated id
attribute to distiguish the cloned object from the original object.
Contact
remove
Remove the current contact from the address book.
In the case that the current id
attribute is NULL
and this method is invoked, a ContactErrorCB
must be
triggered as part of the remove contact process. This error must consist of a ContactError
object with a code
of
ContactError::CONTACT_NOT_FOUND_ERROR
.
This method takes one or two arguments. When called, it immediately returns
a PendingOp
object , as defined in [CORE-DEVICE], and then asynchronously starts a remove contact process defined as follows:
Contacts
.successCB
. If the attempt fails, and the method was
invoked with a non-null
errorCB
argument, this method must invoke the
errorCB
with a ContactError
object as an argument.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
successCB |
| ✘ | ✘ | Function to call when the asynchronous operation completes |
errorCB |
| ✔ | ✔ | Function to call when the asynchronous operation fails. |
PendingOp
save
Add or update (as appropriate) the current Contact
object to the Contacts
.
In the case that the name
attribute is null
and this method is invoked, an ContactErrorCB
must be
triggered as part of the save contact process. This error must consist of a ContactError
object with a code
of
ContactError::CONTACT_INVALID_ERROR
.
This method takes one or two arguments. When called, it immediately returns
a PendingOp
object , as defined in [CORE-DEVICE], and then asynchronously starts a save contact process defined as follows:
Contact.id
already exists in Contacts
then update the existing object in Contacts
.Contact.id
value does not current exist in Contacts
or the current Contact.id
value has not been set, add the current object as a new object to Contacts
.successCB
. If the attempt fails, and the method was
invoked with a non-null
errorCB
argument, this method must invoke the
errorCB
with a ContactError object as an argument.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
successCB |
| ✘ | ✘ | Function to call when the asynchronous operation completes |
errorCB |
| ✔ | ✔ | Function to call when the asynchronous operation fails. |
PendingOp
ContactProperties
interface
The ContactProperties
interface captures the settable properties of a contact.
ContactProperties
is used as part of the Contact
object. ContactProperties
can also be used as the basis of the Contacts.find()
searches within the address book.
Attributes of the ContactProperties
interface that expect a singular value have singular spelling (e.g. name
) and attributes that may have one or more values have plural spelling (e.g. phones
) to make the distinction of these fields easier.
When ContactProperties
is used as an input parameter to Contacts.find()
methods, fields that are set to
null
are considered to match anything.
[NoInterfaceObject]
interface ContactProperties {
attribute DOMString? name;
attribute DOMString[] nicknames;
attribute ContactField
[] phones;
attribute ContactField
[] emails;
attribute ContactAddress
[] addresses;
[PutForwards=value]
attribute ContactField
[] impps;
attribute DOMString? serviceId;
attribute DOMString[] categories;
};
addresses
of type array of ContactAddress
Aligned with Geolocation v2 specification.
One or more addresses associated with the contact.
The first object in this sequence is inferred to be the user's preferred/default address.
{addresses: [{streetNumber: '123', street: 'Main Street', city: 'My Town', region: 'CA', postalCode: '91921-1234', country: 'USA'}]}
categories
of type array of DOMStringOne or more contact categories/groups to associate the contact with.
{categories: ['friends', 'w3c', 'information technology', 'engineers']}
emails
of type array of ContactField
One or more email addresses associated with the contact.
The first object in this sequence is inferred to be the user's preferred/default email address.
The following constants are defined for use in the types
attribute for email addresses:
'home', 'work', 'personal', 'business'.
Additional values may be provided for the types
attribute.
{emails: [{types: ['work'], value: 'john.q.quinlan@example.com'}, {types: ['home', 'mobile'], value: 'jquinlan@mail.com'}]}
impps
of type array of ContactField
One or more instant messaging and presence protocol addresses associated with the contact.
The first object in this sequence is inferred to be the user's preferred/default instant messaging and presence protocol address.
The following constants are defined for use in the types
attribute for instant messaging and presence protocol addresses:
'home', 'work', 'personal', 'business'.
Additional values may be provided for the types
attribute.
{impps: [{types: ['work'], value:'im:jquinlan@example.com'}, {types: ['work', 'mobile'], value:'sip:jquinlan@example.com'}]}
name
of type DOMString, nullableThe contact's name represented in a formatted manner
Each contact must include a non-empty name
value.
{name: 'Mr. John Q. Public, Esq.'}
nicknames
of type array of DOMStringOne or more nicknames associated with the contact
{nicknames: ['jim', 'jimmie']}
phones
of type array of ContactField
One or more telephone numbers associated with the contact.
The first object in this sequence is inferred to be the user's preferred/default phone number.
The following constants are defined for use in the types
attribute for phone numbers:
'home', 'work', 'voice', 'fax', 'fixed', 'mobile', 'car', 'video', 'isdn', 'pager', 'modem', 'pcs'.
Additional values may be provided for the types
attribute.
{phones: [{types: ['home'], value: '+442088450343'}, {types: ['work'], value: '+442088450343'}] }
serviceId
of type DOMString, nullableAn identifier that may be provided that represents the address book owner of the current contact object.
This attribute enables multiple address book sources to be tagged and filtered on Contact objects.
It is recommended that an implementation assign the serviceId attribute as a URI.
{serviceId: 'http://example.com/myservices/v1/addressbook'}
ContactField
interface
The ContactField/Field interface is a reusable component that is used to support contact fields within the ContactProperties
interface.
It defines an optional types
parameter that can be provided with a standard value
.
[NoInterfaceObject]
interface ContactField {
attribute sequence<DOMString>? types;
attribute DOMString value;
};
ContactAddress
interface
The ContactAddress interface is a reusable component that is used to support address information within the ContactProperties
interface.
[NoInterfaceObject]
interface ContactAddress {
attribute DOMString country;
attribute DOMString region;
attribute DOMString county;
attribute DOMString city;
attribute DOMString street;
attribute DOMString streetNumber;
attribute DOMString premises;
attribute DOMString additionalInformation;
attribute DOMString postalCode;
};
additionalInformation
of type DOMStringContactAddress
properties.
city
of type DOMStringcountry
of type DOMStringcounty
of type DOMStringregion
.
postalCode
of type DOMStringpremises
of type DOMStringregion
of type DOMStringstreet
of type DOMStringstreetNumber
of type DOMStringContactOptions
interfaceRename this to "ContactSearchFilter" or similar?
The ContactOptions
interface describes the options that can be applied to contact searching.
[NoInterfaceObject]
interface ContactOptions {
attribute unsigned short limit;
attribute unsigned short page;
attribute DOMString? sort;
attribute boolean? group;
};
group
of type boolean, nullable
The ECMA-262 specification says in, section 12.6.4, "[for the for-in Statement t]he mechanics and order of enumerating the
properties [...] is not specified."
However, all major browsers loop over the properties of an object in the order in which they were defined (ref:
JavaScript in Chrome blog post
but independently verified). Chrome has some minor issues, but due to the overwhelming implementation of this behaviour in all other major browsers,
the Chrome development team have marked this as a bug and it is due for fix in an upcoming release
[2].
Whether the first property in the related ContactProperties
object (in the order in which those properties were defined) should be grouped.
Only the first ContactProperties
property provided can be grouped.
limit
of type unsigned shortThe maximum number of results to return from the contacts search.
If no value is provided, the search will return all search results.
page
of type unsigned shortThe page number of the contacts search to return. If the requested page index does not exist, this parameter must be assigned the default value.
If no value is provided, the search will return all search results.
sort
of type DOMString, nullable
The ECMA-262 specification says in, section 12.6.4, "[for the for-in Statement t]he mechanics and order of enumerating the
properties [...] is not specified."
However, all major browsers loop over the properties of an object in the order in which they were defined (ref:
JavaScript in Chrome blog post
but independently verified). Chrome has some minor issues, but due to the overwhelming implementation of this behaviour in all other major browsers,
the Chrome development team have marked this as a bug and it is due for fix in an upcoming release
[2].
Would it be better to have sort: ['field1', 'field2'] and descending: true|false where the latter is only meaningful if sort was specified?
The direction in which to sort the first property in the related ContactProperties
object (in the order in which those properties were defined).
Only the first ContactProperties
property provided is sortable.
This attribute must be one of the following constants:
'asc', 'desc'
If a different value is provided, this field defaults to null
ContactFindSuccessCB
interface[Callback=FunctionOnly, NoInterfaceObject]
interface ContactFindSuccessCB {
void onSuccess (in sequence<Contact
> contactObjs);
};
ContactSuccessCB
interface[Callback=FunctionOnly, NoInterfaceObject]
interface ContactSuccessCB {
void onSuccess (in Contact
contactObj);
};
ContactErrorCB
interface[Callback=FunctionOnly, NoInterfaceObject]
interface ContactErrorCB {
void onError (in ContactError
error);
};
onError
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
error |
| ✘ | ✘ | The Contact API related error object of an unsuccessful asynchronous operation. |
void
ContactError
interfaceAdd Contacts API specific error codes...
The ContactError
interface encapsulates all errors in the manipulation of Contact
objects in the Contacts API.
[NoInterfaceObject]
interface ContactError : GenericError
{
const unsigned short CONTACT_NOT_FOUND_ERROR = 30;
const unsigned short CONTACT_INVALID_ERROR = 31;
};
CONTACT_INVALID_ERROR
of type unsigned shortContact
object does not include all mandatory attributes required in Contacts
.
CONTACT_NOT_FOUND_ERROR
of type unsigned shortContact
object requested could not be found in Contacts
.
The following interfaces may be general interfaces for use throughout all APIs. They are included here for now for API spec completion.
GenericError
interface
The GenericError
interface encapsulates all general errors and is the basis of all errors produced by DAP APIs.
[NoInterfaceObject]
interface GenericError {
const unsigned short UNKNOWN_ERR = 0;
const unsigned short INVALID_ARGUMENT_ERROR = 1;
const unsigned short NOT_FOUND_ERROR = 2;
const unsigned short PENDING_OPERATION_ERROR = 3;
const unsigned short IO_ERROR = 4;
const unsigned short NOT_SUPPORTED_ERROR = 5;
const unsigned short PERMISSION_DENIED_ERROR = 20;
readonly attribute unsigned short code;
};
code
of type unsigned short, readonlyINVALID_ARGUMENT_ERROR
of type unsigned shortIO_ERROR
of type unsigned shortNOT_FOUND_ERROR
of type unsigned shortNOT_SUPPORTED_ERROR
of type unsigned shortPENDING_OPERATION_ERROR
of type unsigned shortPendingOp
(as defined in [CORE-DEVICE]) associated with the requested callback produces an error on cancel()
.
PERMISSION_DENIED_ERROR
of type unsigned shortUNKNOWN_ERR
of type unsigned short
The Contacts
interface find() method
provides a method to search for contacts according to the input of a
ContactProperties
object.
All fields within a ContactProperties
object provided to this method represent a logical UNION of value matching.
Fields provided with a null
value are considered to match anything.
For example, the following ContactProperties
object is supplied for Contact searching:
navigator.contacts.find({ name:'Robert', nicknames:['Bob'] }, /*...*/);The above example logically implies: "find contact objects that contain a name of 'Robert' AND a nickname of 'Bob'".
We need to be a lot clearer about partial matching included below. It might just be simpler to use pass RegExp objects around. Then again it might not...
All contact searching should apply a loose-matching policy. If a ContactProperties
attribute being searched in Contacts
partially matches the input filter value, a Contact
object representing the contact
should be returned as part of the resulting ContactFindSuccessCB
.
The rules for processing filter combinations is defined below and is always provided with an input parameter and, an optional options parameter. Its behaviour depends on the type of input:
null
, go to step 2.null
. apply the provided options to contactsset.Return a null
value.
The requirements document contains a list of features that were considered for this version but deferred to future work [DAP-REQS].
The editor would like to thank the input from the PhoneGap, Nokia, and OMTP BONDI groups and the feedback received from W3C DAP members to date ...