It’s time for another round on the Ubuntu Technical Board’s review of the top ranked items on Ubuntu Brainstorm. This time I’m reviewing a brainstorm about a Unity Lens for contacts, together with Neil Patel from Canonical’s DX team. I volunteered to participate in this reply because I’d already been thinking about how to do it before I saw the brainstorm. I mainly keep my contacts in Gmail these days, for sync to my Android phone and tablet. But, with around 700 contacts, I find the Gmail interface pretty clunky.

The first key to a Contacts Lens is a standard format for contacts, and a path for contact synchronization. For the Oneiric release, coming up in a couple of weeks, Thunderbird is the new default email client, and as part of that, the Thunderbird developers (especially Mike Conley) added support to Thunderbird for the existing standard for contacts in GNOME, which is EDS (Evolution Data Server). Supporting EDS not only provides access to Evolution contacts from Thunderbird, which is important for users migrating from Evolution to Thunderbird, but also provides access to Gmail contacts and UbuntuOne contacts.

The second key is integrating EDS with a Unity Lens. The DX team isn’t working on a Contacts Lens for this in Oneiric or 12.04, but writing a lens is an accessible task for anyone with a little skill in Vala or Python, and is a great way to learn more about how Unity works. I’ll outline how to get started here, for more details see the wiki documentation on lenses. The architecture of a Unity Lens is pretty simple, I’d even say elegant. Writing a Lens doesn’t involve any GUI code at all, you only write a small backend that supplies the data to be displayed. This means that all lenses work for both Unity and Unity 2D, without any changes.

A Lens is a daemon that talks over D-Bus. To build one, you start with 3 files. (Throughout this illustration, I’ll pretend we’re working on a Launchpad project called ‘unity-lens-contacts’.)  The first file is the Lens itself, and the core of that file is a few lines that create a Lens object from libunity, and then set some default properties for it. In Vala, that would be:

lens = new Unity.Lens("/net/launchpad/lens/contacts", "contacts");

To go along with the Lens, you need a ‘contacts.lens’ file to tell Unity where to find your daemon, and a ‘contacts.service’ file to register the D-Bus service that your Lens provides. The ‘contacts.lens’ file is installed in ‘/usr/share/unity/lenses/contacts/’, and looks like:

\[Lens\]
DBusName=net.launchpad.Lens.Contacts
DBusPath=/net/launchpad/lens/contacts
Name=Contacts
Icon=/usr/share/unity-lens-contacts/data/lens-nav-contacts.svg
Description=A Lens to search contacts
SearchHint=Search Contacts
Shortcut=c

\[Desktop Entry\]
X-Ubuntu-Gettext-Domain=unity-lens-contacts

The ‘contacts.service’ file is installed in ‘/usr/share/dbus-1/services/’, and looks like:

\[D-BUS Service\]
Name=net.launchpad.Lens.Contacts
Exec=/usr/lib/unity-lens-contacts/unity-lens-contacts

A Lens daemon handles requests for data, but it doesn’t actually do the searching. For that, you need to define a Scope (if it helps, think about searching the ocean through a periscope). A Lens can have more than one Scope, and when it does, each Scope collects results from a different source, so the Lens can combine them into one full set of results. Start with one Scope for one datasource: EDS contacts. A Scope is just another libunity object, and creating one in Vala looks like:

scope = new Unity.Scope ("/net/launchpad/scope/edscontacts");

The search functionality goes in the ‘perform_search’ method. For EDS contacts, you could use the EDS APIs directly, but Neil recommends libfolks. A Scope can run locally inside the Lens daemon, in which case you add it directly to the Lens object:

lens.add\_local\_scope(scope);

Or, a Scope can run in a separate daemon, in which case you’ll also need an ’edscontacts.scope’ file, so the Lens knows where to find the Scope. This file is installed in the same folder as ‘contacts.lens’ (’/usr/share/unity/lenses/contacts/’), and looks like:

\[Scope\]
DBusName=net.launchpad.Scope.edscontacts
DBusPath=/net/launchpad/scope/edscontacts

That’s the basic anatomy of a Lens, and enough to get a new project started. To see how it all fits together, there are several good examples of other lenses. The Unity Music Lens is the most relevant example for the Contacts Lens, and a fairly straightforward one to start looking at. For more complex examples, see the Applications or Files lenses. There’s also a Sample Lens, which is a working tutorial. And, once you get the core of the Contacts Lens working, and are looking for what to add next, read up more on Categories and Filters in the wiki. If this sounds like an interesting project to you, drop us a line. You’ll find a lot of enthusiasm, and willingness to help out where you need it.