Documentation/Maemo 5 Developer Guide/Using Data Sharing/Sharing Plug-in

m (Service XML File)
(use <source> and <code>, wikify slightly, tidy)
 
(One intermediate revision not shown)
Line 1: Line 1:
-
=Using Sharing dialog API=
+
With the Sharing dialog API, the user can open the first dialog, which starts the Sharing flow. From the first dialog the user can select "Send via Bluetooth", "Send via E-mail" and "Share via service".
-
With Sharing dialog API user can open the first dialog, which start the Sharing flow. From the first dialog user can select "Send via Bluetooth", "Send via E-mail" and "Share via service".
+
More detailed API documentation can be found from [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin here].
More detailed API documentation can be found from [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin here].
Line 6: Line 5:
Example code how to use the API:
Example code how to use the API:
-
  /* create osso context in your app that is passed to sharing */
+
<source lang="c">
-
  osso_context_t *osso = osso_initialize ("my_app", "1.0.0.", FALSE, NULL);
+
/* create osso context in your app that is passed to sharing */
-
  /* file to open */
+
osso_context_t *osso = osso_initialize ("my_app", "1.0.0.", FALSE, NULL);
-
  gchar *filename = "/path/to/file";
+
/* file to open */
-
  sharing_dialog_with_file (osso,
+
gchar *filename = "/path/to/file";
-
                            GTK_WINDOW (parent),
+
sharing_dialog_with_file (osso,
-
                            filename);
+
                          GTK_WINDOW (parent),
 +
                          filename);
 +
</source>
In the example above we use the API to start sharing single file. In case you want to share simultaneously more than one file or you want
In the example above we use the API to start sharing single file. In case you want to share simultaneously more than one file or you want
to change what button are seen in the dialog use one of the functions below.
to change what button are seen in the dialog use one of the functions below.
 +
<source lang="c">
  void sharing_dialog_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris);
  void sharing_dialog_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris);
  void sharing_dialog_button_mask_with_file (osso_context_t * osso, GtkWindow * parent, const gchar * uris, guint share_button_mask);
  void sharing_dialog_button_mask_with_file (osso_context_t * osso, GtkWindow * parent, const gchar * uris, guint share_button_mask);
  void sharing_dialog_button_mask_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris, guint share_button_mask);
  void sharing_dialog_button_mask_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris, guint share_button_mask);
 +
</source>
==Compiling==
==Compiling==
-
When compiling your application use the following pkg-config configuration.
+
 
 +
When compiling your application use the following pkg-config configuration:
  `pkg-config --cflags --libs sharingdialog`
  `pkg-config --cflags --libs sharingdialog`
-
=Writing "Send Via" Functionality to E-mail and Bluetooth=
+
==Writing "Send Via" Functionality for E-mail and Bluetooth==
-
Send Via E-mail and Bluetooth can be used directly without Sharing dialog
+
Send Via E-mail and Bluetooth can be used directly without Sharing dialog and the functionality is provided by the platform to enable applications to send data via E-mail or over a Bluetooth connection. Because several applications share this functionality, the platform provides a public interface to facilitate the deployment of these services in user applications. The interfaces are defined in two header files: <code>libmodest-dbus-client.h</code> (in the <code>libmodest-dbus-client-dev</code> package) and <code>conbtdialogs-dbus.h</code> (in the <code>conbtdialogs-dev</code> package). The following sample code is an example of the usage of these interfaces. See the maemopad source code available in the SDK repository for a fully functional application using this service.
-
and the functionality is provided by the platform to enable applications to send data via E-mail or over a Bluetooth connection. Because several applications share this functionality, the platform provides a public interface to facilitate the deployment of these services in user applications. The interfaces are defined in two header files: libmodest-dbus-client.h (in the libmodest-dbus-client-dev package) and conbtdialogs-dbus.h (in the conbtdialogs-dev package). The following sample code is an example of the usage of these interfaces. See the maemopad source code available in the SDK repository for a fully functional application using this service.
+
maemopad/src/maemopad-window.c
maemopad/src/maemopad-window.c
-
/* send via email: */
+
<source lang="c">
-
#include <libmodest-dbus-client/libmodest-dbus-client.h>
+
/* send via email: */
-
/* send via bt: */
+
#include <libmodest-dbus-client/libmodest-dbus-client.h>
-
#include <conbtdialogs-dbus.h>
+
/* send via bt: */
-
/*......*/
+
#include <conbtdialogs-dbus.h>
-
static void maemopad_window_on_menu_sendvia_email (GtkButton *button, gpointer data)
+
/*......*/
-
{
+
static void maemopad_window_on_menu_sendvia_email (GtkButton *button, gpointer data)
-
  MaemopadWindow *self = MAEMOPAD_WINDOW (data);
+
{
-
  gboolean result = TRUE;
+
MaemopadWindow *self = MAEMOPAD_WINDOW (data);
-
  GSList *list = NULL;
+
gboolean result = TRUE;
-
  g_assert (self);
+
GSList *list = NULL;
-
  /* Attach the saved file (and not the one currently on screen). If the file  
+
g_assert (self);
-
  * has not been saved yet, nothing is attached */
+
/* Attach the saved file (and not the one currently on screen). If the file  
-
  if (self->file_name) {
+
  * has not been saved yet, nothing is attached */
-
  list = g_slist_append(list, self->file_name);
+
if (self->file_name) {
-
  result = libmodest_dbus_client_compose_mail(self->osso, /*osso_context_t*/
+
  list = g_slist_append(list, self->file_name);
-
    NULL, /*to*/
+
  result = libmodest_dbus_client_compose_mail(self->osso, /*osso_context_t*/
-
    NULL, /*cc*/
+
    NULL, /*to*/
-
    NULL, /*bcc*/
+
    NULL, /*cc*/
-
    NULL, /*body*/
+
    NULL, /*bcc*/
-
    NULL, /*subject*/
+
    NULL, /*body*/
-
    list /*attachments*/);
+
    NULL, /*subject*/
-
  }
+
    list /*attachments*/);
-
  g_slist_free(list);
+
-
  if (result == FALSE)
+
-
  g_print("Could not send via email\n");
+
  }
  }
 +
g_slist_free(list);
 +
if (result == FALSE)
 +
  g_print("Could not send via email\n");
 +
}
-
static gboolean maemopad_window_rpc_sendvia_bluetooth (const gchar *path)
+
static gboolean maemopad_window_rpc_sendvia_bluetooth (const gchar *path)
 +
{
 +
DBusGProxy *proxy = NULL;
 +
DBusGConnection *sys_conn = NULL;
 +
GError *error = NULL;
 +
gboolean result = TRUE;
 +
gchar **files = NULL;
 +
/*sys_conn = osso_get_sys_dbus_connection(ctx);*/
 +
sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
 +
if(sys_conn == NULL)
  {
  {
-
   DBusGProxy *proxy = NULL;
+
   return FALSE;
-
  DBusGConnection *sys_conn = NULL;
+
-
  GError *error = NULL;
+
-
  gboolean result = TRUE;
+
-
  gchar **files = NULL;
+
-
  /*sys_conn = osso_get_sys_dbus_connection(ctx);*/
+
-
  sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
+
-
  if(sys_conn == NULL)
+
-
  {
+
-
  return FALSE;
+
-
  }
+
-
  files = g_new0(gchar*, 2);
+
-
  *files = g_strdup(path);
+
-
  files[1] = NULL;
+
-
  /* Open connection for btdialogs service */
+
-
  proxy = dbus_g_proxy_new_for_name(sys_conn,
+
-
  CONBTDIALOGS_DBUS_SERVICE,
+
-
  CONBTDIALOGS_DBUS_PATH,
+
-
  CONBTDIALOGS_DBUS_INTERFACE);
+
-
  /* Send send file request to btdialogs service */
+
-
  if (!dbus_g_proxy_call(proxy, CONBTDIALOGS_SEND_FILE_REQ,
+
-
  &error, G_TYPE_STRV, files,
+
-
  G_TYPE_INVALID, G_TYPE_INVALID))
+
-
  {
+
-
  g_print("Error: %s\n", error->message);
+
-
  g_clear_error (&error);
+
-
  result = FALSE;
+
-
  }
+
-
  g_strfreev(files);
+
-
  g_object_unref(proxy);
+
-
  return result;
+
  }
  }
 +
files = g_new0(gchar*, 2);
 +
*files = g_strdup(path);
 +
files[1] = NULL;
 +
/* Open connection for btdialogs service */
 +
proxy = dbus_g_proxy_new_for_name(sys_conn,
 +
  CONBTDIALOGS_DBUS_SERVICE,
 +
  CONBTDIALOGS_DBUS_PATH,
 +
  CONBTDIALOGS_DBUS_INTERFACE);
 +
/* Send send file request to btdialogs service */
 +
if (!dbus_g_proxy_call(proxy, CONBTDIALOGS_SEND_FILE_REQ,
 +
  &error, G_TYPE_STRV, files,
 +
  G_TYPE_INVALID, G_TYPE_INVALID))
 +
{
 +
  g_print("Error: %s\n", error->message);
 +
  g_clear_error (&error);
 +
  result = FALSE;
 +
}
 +
g_strfreev(files);
 +
g_object_unref(proxy);
 +
return result;
 +
}
 +
</source>
 +
 +
==Writing Sharing Plug-in for "Send via Service"==
-
=Writing Sharing Plug-in for "Send via Service"=
+
Maemo 5 introduces a new library for handling Sharing related information and services. This chapter will walk you through the process of creating a sharing plug-in using a template plug-in as example. Basic knowledge of Debian development and working in a Scratchbox environment is needed in order to follow these guides.
-
Maemo 5 introduces a new library for handling Sharing related information and services. This chapter will walk you through the process of creating a sharing plug-in using a template plug-in as example. Basic knowledge of debian development and working in scratchbox environment is needed in order to follow these guides.
+
Plugin template with some example codes is located here [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/data-sharing-plugin/ Data Sharing Plugin example]
Plugin template with some example codes is located here [https://vcs.maemo.org/svn/maemoexamples/tags/maemo_5.0/data-sharing-plugin/ Data Sharing Plugin example]
Line 101: Line 107:
Detailed API documentation is available in [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/ libsharing-plugin-doc] package in gtk-doc format.
Detailed API documentation is available in [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/ libsharing-plugin-doc] package in gtk-doc format.
-
Before starting to create your own plugin it's good idea to check the default services OVI and Flickr. From those you can see two different UI flows for creating account.
+
Before starting to create your own plugin it is a good idea to check the default services: OVI and Flickr. From those you can see two different UI flows for creating accounts. In OVI the UI flow is pretty simple and clear, you just type a user name and password and then validate the account. In Flickr the flow is more complex, as before validation the user must login to Flickr via a web page to get authentication and continue the validation after that.  
-
In OVI the UI flow is pretty simple and clear, you just type user name and password and then validate the account. In Flickr the flow is more complex as before validation user must login to Flickr web page to get authentication and continue the validation after that.  
+
Account creation is started from Settings:
Account creation is started from Settings:
  Settings -> Sharing accounts -> New -> Select service ...
  Settings -> Sharing accounts -> New -> Select service ...
-
==Sharing User Interfaces==
+
===Sharing User Interfaces===
-
Sharing application abstracts the file sharing and implements common parts needed for file sharing application. Sharing Application service support can be extended by using Sharing Plug-ins. These plug-ins can be created by any 3rd party developer. The plug-ins should implement the Sharing Plug-in API functions and define some parameters to service definition XML file.
+
 
 +
Sharing application abstracts the file sharing and implements common parts needed for file sharing application. Sharing Application service support can be extended by using Sharing Plug-ins. These plug-ins can be created by any 3rd party developer. The plug-ins should implement the Sharing Plug-in API functions and define some parameters in a service definition XML file.
Figure 1 below shows Sharing accounts dialog opened from the control panel. With the Sharing accounts, you can create a new Sharing account or edit an existing one. If you install a custom Sharing plug-in, you can see the service it provides in the "Select service list" when creating a new Sharing account.
Figure 1 below shows Sharing accounts dialog opened from the control panel. With the Sharing accounts, you can create a new Sharing account or edit an existing one. If you install a custom Sharing plug-in, you can see the service it provides in the "Select service list" when creating a new Sharing account.
Line 118: Line 124:
-
Figure 2 shows the Sharing Dialog user interface that is used to share images to the selected account on some service. The images displayed can come for example from Photos application or from the device camera. You can choose the account created for your service from the "Account" combo box which holds all existing Sharing accounts.
+
Figure 2 shows the Sharing Dialog user interface that is used to share images with the selected account on some service. The images displayed can come for example from the Photos application or from the device camera. You can choose the account created for your service from the "Account" combo box which holds all existing Sharing accounts.
[[Image:SharingDialogInterface.png]]
[[Image:SharingDialogInterface.png]]
Line 124: Line 130:
''Figure 2: Sharing Dialog User Interface''
''Figure 2: Sharing Dialog User Interface''
-
==Getting Familiar With Target Service API==
+
===Getting Familiar With Target Service API===
-
Many web services provide APIs that are available for 3rd party developers. In this tutorial, we focus on services that provide APIs for image and video uploads. It is possible to give title, description and tags for the images using the common service API.
+
 
-
Sharing supports image scaling and meta data filtering as common options for any service. Sharing Plug-ins can have service specific options, like privacy. These settings can be accessed through Options dialog (in Figure 2.)
+
Many web services provide APIs that are available for 3rd party developers. In this tutorial, we focus on services that provide APIs for image and video uploads. It is possible to give a title, description and tags for the images using the common service API. Sharing supports image scaling and metadata filtering as common options for any service. Sharing Plug-ins can have service-specific options, like privacy. These settings can be accessed through the Options dialog (in Figure 2.)
 +
 
 +
===Getting Your Dummy Plugin To Sharing Menus===
 +
 
 +
As a prerequisite, you will need a working Maemo 5 SDK to continue further. We will first install the Sharing Plug-in template:
-
==Getting Your Dummy Plugin To Sharing Menus==
+
* Obtain the template source code ''sharing-plugin-template-0.1.tar.gz'' from [https://garage.maemo.org/svn/maemoexamples/trunk/data-sharing-plugin/ the maemoexamples repository]. It contains a good start up file structure for creating a plugin.
-
As a pre-requisite, you will need a working Maemo 5 SDK to continue further.
+
* Extract and build the package from the folder using command:
-
We will first install the Sharing Plug-in template:
+
-
*Obtain the template source code ''sharing-plugin-template-0.1.tar.gz'' from <URL HERE>. It contains a good start up file structure for the plug-in creation.
+
-
*Extract and build the package from the folder using command:
+
  ./autogen.sh; dpkg-buildpackage -rfakeroot -d
  ./autogen.sh; dpkg-buildpackage -rfakeroot -d
-
*Install the package built to your Scratchbox environment or to device if it was build with ARM target.
+
* Install the package built for your Scratchbox environment or to the device if it was built with the ARM target.
*The template dummy service should be now visible in the Sharing account when creating new accounts.  
*The template dummy service should be now visible in the Sharing account when creating new accounts.  
-
<div style="border: 2px solid rgb(255, 215, 0); background-color: rgb(252, 233, 79); margin-left: 25px; margin-right: 25px; padding: 2px"> N.B: Note that this template plug-in does not send any data before you write the implementation for it. </div>
+
{{ambox
 +
|text=Note that this template plugin does not send any data before you write the implementation for it.
 +
}}
==Editing Template Plug-in==
==Editing Template Plug-in==
-
In this section, we peek under the hood by opening the files found from the template plug-in and get familiar with Sharing classes that are used in the Sharing Plugin API functions.
+
 
 +
In this section, we peek under the hood by opening the files found from the template plugin and get familiar with Sharing classes that are used in the Sharing Plugin API functions.
===Sharing Internals===
===Sharing Internals===
-
Figure 3 shows the general overview of how Sharing Plug-in connects to Sharing Application using the Sharing Plug-in API. The basic plug-in components are the service definition file and the plug-in library. The Application Sharing-Dialog is used to create ''SharingEntries'' that are shared by ''SharingManager''. Sharing Account Manager implements the Sharing Accounts. Libsharing is library for all common Sharing functionality.
+
 
 +
Figure 3 shows the general overview of how Sharing Plug-in connects to Sharing Application using the Sharing Plugin API. The basic plug-in components are the service definition file and the plugin library. The Application Sharing-Dialog is used to create <code>SharingEntries</code> that are shared by a <code>SharingManager</code>. Sharing Account Manager implements the Sharing Accounts. Libsharing is a library for all common Sharing functionality.
[[Image:SharingPluginAPI.jpg]]
[[Image:SharingPluginAPI.jpg]]
Line 150: Line 161:
-
Figure 4 shows the common ''Sharing'' classes found in ''libsharing'' that you would use while creating the plug-in.
+
Figure 4 shows the common ''Sharing'' classes found in ''libsharing'' that you would use while creating the plug-in:
-
''SharingTransfer'' is the object that contains all the data of sharing task, overall status of the transfer process for one set of shared files.  
+
* <code>SharingTransfer</code> is the object that contains all the data of a sharing task, overall status of the transfer process for one set of shared files.  
-
''SharingEntry'' contains the the ''SharingEntryMedia'' that are the selected files. It also knows the ''SharingAccount'' that is the target of sharing.  
+
* <code>SharingEntry</code> contains the <code>SharingEntryMedia</code> that are the selected files. It also knows the <code>SharingAccount</code> that is the target of sharing.
-
''SharingAccount'' contains the username and password along with other parameters that you have to save for your service's accounts. It also has the information about ''SharingService'' which is registered to the ''SharingAccount''.
+
* <code>SharingAccount</code> contains the username and password along with other parameters that you have to save for your service's accounts. It also has the information about <code>SharingService</code> which is registered with the <code>SharingAccount</code>.
[[Image:LibSharingClasses.jpg]]
[[Image:LibSharingClasses.jpg]]
Line 162: Line 173:
===Service XML File===
===Service XML File===
-
Service definition file, data/template.service.xml.in is the starting point for plug-in loading. It defines the library that implements Sharing Plug-in API functions, the sign up URL for totally new account creation by using web browser, service name, icon file names and some basic information from plug-in.
 
-
<?xml version="1.0" encoding="UTF-8"?>  
+
The service definition file, <code>data/template.service.xml.in</code> is the starting point for plugin loading. It defines the library that implements Sharing Plugin API functions, the sign up URL for totally new account creation using a web browser, the service name, icon file names and some basic information from plug-in.
-
<service plugin="libtemplate.so" provider="Me">  
+
 
-
+
<source lang="xml">
-
    <accounts plugInSetup="0" plugInEdit="0">
+
<?xml version="1.0" encoding="UTF-8"?>  
-
      <signup>www.maemo.org</signup>  
+
<service plugin="libtemplate.so" provider="Me">  
-
      <password maxlen="32"/>  
+
 
-
    </accounts>  
+
  <accounts plugInSetup="0" plugInEdit="0">
-
+
    <signup>www.maemo.org</signup>  
-
    <ui>  
+
    <password maxlen="32"/>  
-
        <name>Template</name>   
+
  </accounts>  
-
        <icon type="post">@servicesdir@/template-post.png</icon>  
+
 
-
        <icon type="setup">@servicesdir@/template-setup.png</icon>  
+
  <ui>  
-
        <options>  
+
      <name>Template</name>   
-
            <option id="privacy" type="enumeration" default="private">  
+
      <icon type="post">@servicesdir@/template-post.png</icon>  
-
                <caption domain="osso-sharing-ui" key="share_bd_options_privacy"/>  
+
      <icon type="setup">@servicesdir@/template-setup.png</icon>  
-
                <value id="private" domain="osso-sharing-ui" key="share_fi_options_privacy_private"/>  
+
      <options>  
-
                <value id="public" domain="osso-sharing-ui" key="share_fi_options_privacy_public"/>
+
          <option id="privacy" type="enumeration" default="private">  
-
                </option>
+
              <caption domain="osso-sharing-ui" key="share_bd_options_privacy"/>  
-
        </options>
+
              <value id="private" domain="osso-sharing-ui" key="share_fi_options_privacy_private"/>  
-
    </ui>
+
              <value id="public" domain="osso-sharing-ui" key="share_fi_options_privacy_public"/>
-
</service>
+
              </option>
 +
      </options>
 +
    </ui>
 +
</service>
 +
</source>
''File 1: Example service definition XML file''
''File 1: Example service definition XML file''
-
''' How to read the xml file:'''
+
==== How to read the xml file ====
The prefix of the xml file name defines the used service id of the plugin. In our example the id is "template".
The prefix of the xml file name defines the used service id of the plugin. In our example the id is "template".
Service element:
Service element:
-
<service plugin="" provider="">
+
<source lang="xml">
-
...
+
<service plugin="" provider="">
-
</service>
+
...
-
*Service is the root node of each service xml and must be named exactly "service".
+
</service>
-
*Property '''plugin''' defines the library name that Sharing will look from /usr/lib/sharing.
+
</source>
-
*Property '''provider''' defines the plugin provider.
+
* Service is the root node of each service xml and must be named exactly <code>service</code>.
 +
* Property <code>plugin</code> defines the library name that Sharing will look for in <code>/usr/lib/sharing</code>.
 +
* Property <code>provider</code> defines the plugin provider.
Accounts element:
Accounts element:
-
<accounts plugInSetup="0" plugInEdit="0">
+
<source lang="xml">
-
  <signup>www.myservicepage.com</signup>  
+
<accounts plugInSetup="0" plugInEdit="0">
-
</accounts>  
+
  <signup>www.myservicepage.com</signup>  
-
*Accounts element defines the account setup options.
+
</accounts>
-
*Property '''plugInSetup''' defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
+
</source>
-
*Property '''plugInEdit''' defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
+
* Accounts element defines the account setup options.
-
*Element '''signup''' defines the URL where browser is opened in case default flow used when user press button "Register new account" in account setup dialog.
+
* Property <code>plugInSetup</code> defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
 +
* Property <code>plugInEdit</code> defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
 +
* Element <code>signup</code> defines the URL where browser is opened in case default flow used when user press button "Register new account" in account setup dialog.
Ui element:
Ui element:
-
<ui>  
+
<source lang="xml">
-
  <name>...</name>   
+
<ui>  
-
  <icon type="post">@servicesdir@/...</icon>  
+
  <name>...</name>   
-
  <icon type="setup">@servicesdir@/...</icon>  
+
  <icon type="post">@servicesdir@/...</icon>  
-
  <options>  
+
  <icon type="setup">@servicesdir@/...</icon>  
-
    ...
+
  <options>  
-
  </option>
+
    ...
-
</ui>
+
  </option>
-
*Ui element defines Name, icons and options that can be modified through XML file.
+
</ui>
-
*Element '''name''' defines the name that is shown for the service in all the UI.
+
</source>
-
*Element '''icon''' defines the used icons. Property '''post''' or '''setup''' can be used. Property '''setup''' defines the icon showed in account setup dialogs.
+
* UI element defines Name, icons and options that can be modified through XML file.
-
*Element '''options''' defines the different changeable options for selected service. See more below.
+
* Element <code>name</code> defines the name that is shown for the service in all the UI.
 +
* Element <code>icon</code> defines the used icons. Property <code>post</code> or <code>setup</code> can be used. Property <code>setup</code> defines the icon shown in account setup dialogs.
 +
* Element <code>options</code> defines the different changeable options for selected service. See more below.
Options element:
Options element:
-
<options>
+
<source lang="xml">
-
  <option id="..." type="enumeration || updatable" default="...">  
+
<options>
-
    <caption domain="osso-sharing-ui" key="..."/>  
+
  <option id="..." type="enumeration || updatable" default="...">  
-
    <value id="..." domain="osso-sharing-ui" key="..."/>  
+
    <caption domain="osso-sharing-ui" key="..."/>  
-
  </option>
+
    <value id="..." domain="osso-sharing-ui" key="..."/>  
-
  <option>
+
  </option>
-
  ...
+
  <option>
-
  </option>
+
  ...
-
</options>
+
  </option>
-
*Options element defines all the options that user can change through "Options" for selected service. Each individual option is own element '''option'''.
+
</options>
-
*Property '''id''' defines the internal id for this option. User selected choice for this option is asked with the id, see [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/libsharing-plugin-SharingEntry.html#sharing-entry-get-option here].
+
</source>
-
*Property '''type''' defines the type of option. You can select "enumeration" or "updatable". For the enumeration you need to specify the shown values with values elements. Updatable option can contain default values and rest of values can be updated from service.
+
 
-
*Property '''default''' defines the default value to select if user haven't made any selections yet. Value of default property must mach to one of value element ids.
+
* Options element defines all the options that a user can change through "Options" for the selected service. Each individual option is an element <code>option</code>.
-
*Properties '''domain''' and '''key''' under '''caption''' element defines the actual text to be displayed. If you want to use some localization package then define '''domain''' and wanted logical id to '''key'''. For free text the '''domain''' is not mandatory.
+
* Property <code>id</code> defines the internal id for this option. User selected choice for this option is asked with the id, see [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/libsharing-plugin-SharingEntry.html#sharing-entry-get-option here].
-
*Element '''value''' defines one value in the selection. If option is updatable new values with id/key pair can be added in code, see [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/libsharing-plugin-SharingAccount.html#sharing_account_set_option_values here]. Otherwise you need to specify the shown values.
+
* Property <code>type</code> defines the type of option. You can select <code>enumeration</code> or <code>updatable</code>. For the enumeration you need to specify the shown values with values elements. Updatable option can contain default values and the remaining values can be updated from service.
 +
* Property <code>default</code> defines the default value to select if user haven't made any selections yet. The value of the default property must mach one of the value element ids.
 +
* Properties <code>domain</code> and <code>key</code> under <code>caption</code> element defines the actual text to be displayed. If you want to use some localization package then define <code>domain</code> and desired logical id to <code>key</code>. For free text the <code>domain</code> is not mandatory.
 +
* Element <code>value</code> defines one value in the selection. If option is updatable new values with id/key pair can be added in code, see [http://maemo.org/api_refs/5.0/5.0-final/libsharing-plugin/libsharing-plugin-SharingAccount.html#sharing_account_set_option_values here]. Otherwise you need to specify the shown values.
===Account Setup User Interface Flow===
===Account Setup User Interface Flow===
-
Sharing accounts can either create a default flow where "username" and "password" parameters are set to the account or an optional custom flow. In File 1, the "accounts" tag has a parameter "plugInSetup". If it is set to "1", Sharing Accounts will call the Sharing Plugin API function "sharing_plugin_interface_account_setup" to create UI flow; it will use the default flow.
 
-
You can see the difference between UI flows when creating Flickr and Ovi account. Ovi uses the default flow and Flickr uses it's own UI flow.
 
-
<tt>SharingPluginInterfaceAccountSetupResult sharing_plugin_interface_account_setup (GtkWindow* parent, SharingService* service, SharingAccount** worked_on, osso_context_t* osso)</tt>
+
Sharing accounts can either create a default flow where <code>username</code> and <code>password</code> parameters are set to the account or an optional custom flow. In File 1, the <code>accounts</code> tag has a parameter <code>plugInSetup</code>. If it is set to "1", Sharing Accounts will call the Sharing Plugin API function <code>sharing_plugin_interface_account_setup</code> to create UI flow; it will use the default flow. You can see the difference between UI flows when creating Flickr and Ovi account. Ovi uses the default flow and Flickr uses it's own UI flow.
 +
 
 +
<source lang="c">
 +
SharingPluginInterfaceAccountSetupResult sharing_plugin_interface_account_setup (GtkWindow* parent, SharingService* service, SharingAccount** worked_on, osso_context_t* osso)
 +
</source>
If you decide to create your own account setup flow, please try to keep the same UI look as in other Sharing dialogs.
If you decide to create your own account setup flow, please try to keep the same UI look as in other Sharing dialogs.
===Account Validation===
===Account Validation===
-
Account validation is needed to reduce error cases in actual sending process. Of course you can use the dummy function at template plug-in, but for better user experience this function is recommended to be implemented so that Sharing Account account information is really validated against the service when new account is created.
 
-
Next function is called after sharing_plugin_interface_account_setup call ends or when default account setup flow is done (=when "Validate" button is pressed).
+
Account validation is needed to reduce error cases in the sending process. Of course you can use the dummy function at template plug-in, but for better user experience this function is recommended to be implemented so that Sharing Account account information is really validated against the service when new account is created.
-
<tt>
+
Next function is called after <code>sharing_plugin_interface_account_setup</code> call ends or when default account setup flow is done (when the "Validate" button is pressed).
-
SharingPluginInterfaceAccountValidateResult sharing_plugin_interface_account_validate (SharingAccount* account, ConIcConnection* con, gboolean *cont, gboolean* dead_mans_switch)</tt>
+
-
In the last phase of account creation, the account must be validated. Sharing Plug-in API ''sharing_plugin_interface_test_account'' is the function called in the validation phase of the account creation flow.
+
<source lang="c">
-
Usually web services have a phase in account creation where you have put the needed information from your account, only then you get the actual credentials to upload images if your account information is valid. This is the phase that is implemented in the Sharing Plug-in API function.
+
SharingPluginInterfaceAccountValidateResult sharing_plugin_interface_account_validate (SharingAccount* account, ConIcConnection* con, gboolean *cont, gboolean* dead_mans_switch)
 +
</source>
 +
 
 +
In the last phase of account creation, the account must be validated. Sharing Plug-in API <code>sharing_plugin_interface_test_account</code> is the function called in the validation phase of the account creation flow. Usually web services have a phase in account creation where you have put the needed information from your account, only then you get the actual credentials to upload images if your account information is valid. This is the phase that is implemented in the Sharing Plug-in API function.
===Account Editing User Interface Flow===
===Account Editing User Interface Flow===
-
Sharing Accounts support here too either default flow where “username” and “password” parameters are edited or optional custom edit UI flow. The wanted flow can be set by setting the parameter "plugInEdit" from the service definition file either to "0" or to "1" where "0" means the default flow and "1" plug-in flow.
+
Sharing Accounts support here too either default flow where <code>username</code> and <code>password</code> parameters are edited or optional custom edit UI flow. The desired flow can be set by setting the parameter <code>plugInEdit</code> from the service definition file either to "0" or to "1" where "0" means the default flow and "1" plug-in flow.
The default flow can be used when you need only username and password to get needed information for sending. The plug-in flow is used when you need more than this or customised account validation flow. You can see the difference between UI flows here too when editing Flickr and Ovi accounts.
The default flow can be used when you need only username and password to get needed information for sending. The plug-in flow is used when you need more than this or customised account validation flow. You can see the difference between UI flows here too when editing Flickr and Ovi accounts.
-
Next function must be implemented only when plug-in account setup is used (when "plugInSetup" is set to "1"):
+
Next function must be implemented only when plug-in account setup is used (when <code>plugInSetup</code> is set to "1"):
-
<tt>SharingPluginInterfaceEditAccountResult sharing_plugin_interface_edit_account (GtkWindow* parent, SharingAccount* account, ConIcConnection* con, gboolean* dead_mans_switch)</tt>
+
 
 +
<source lang="c">
 +
SharingPluginInterfaceEditAccountResult sharing_plugin_interface_edit_account (GtkWindow* parent, SharingAccount* account, ConIcConnection* con, gboolean* dead_mans_switch)
 +
</source>
===Sending Functionality===
===Sending Functionality===
-
<tt>SharingPluginInterfaceSendResult sharing_plugin_interface_send (SharingTransfer* transfer, ConIcConnection* con, gboolean* dead_mans_switch)</tt>
+
<source lang="c">
 +
SharingPluginInterfaceSendResult sharing_plugin_interface_send (SharingTransfer* transfer, ConIcConnection* con, gboolean* dead_mans_switch)
 +
</source>
-
After pressing the 'Share' button in Sharing dialog (Figure 2.), the data is put into the Sharing Outbox (can be seen under /home/user/MyDocs/.sharing/outbox/). Sharing manager process is started and the status menu gets the icon to process the new Sharing Entry.
+
After pressing the 'Share' button in Sharing dialog (Figure 2.), the data is put into the Sharing Outbox (can be seen under <code>/home/user/MyDocs/.sharing/outbox/</code>). Sharing manager process is started and the status menu gets the icon to process the new Sharing Entry. <code>SharingHTTP</code> provides an API to create common HTTP requests. In order to create a better user experience following things are good to be implemented after you get the basic functionality working in your plug-in:
-
''SharingHTTP'' provides an API to create common HTTP requests.
+
 
-
In order to create a better user experience following things are good to be implemented after you get the basic functionality working in your plug-in:
+
* Set progress of sending with <code>sharing_transfer_set_progress</code> between 0 and 1 to estimate the current transfer time / total transfer time.
-
*Set progress of sending with sharing_transfer_set_progress between 0 and 1 to estimate the current transfer time / total transfer time.
+
* Set sent to <code>SharingEntryMedia</code> with <code>sharing_entry_media_set_sent</code> when file sending is done and check the send value with <code>sharing_entry_media_get_sent</code> to prevent sending same files multiple times for example in reboot scenarios.
-
*Set sent to ''SharingEntryMedia'' with ''sharing_entry_media_set_sent'' when file sending is done and check the send value with ''sharing_entry_media_get_sent'' to prevent sending same files multiple times for example in reboot scenarios.
+
* Poll cancel flag time to time, for example in curl or <code>SharingHTTP</code> progress function to end transferring when needed. Use <code>sharing_transfer_continue</code> to get the continue flag bit.
-
*Poll cancel flag time to time, for example in curl or ''SharingHTTP'' progress function to end transferring when needed. Use ''sharing_transfer_continue'' to get the continue flag bit.
+
* If you are using ''libcurl'' instead of <code>SharingHTTP</code>, please listen to ''conic'' events to disconnect transfer when no connection available. It returns with 'no connection' return value in this case.
-
*If you are using ''libcurl'' instead of ''SharingHTTP'', please listen to ''conic'' events to disconnect transfer when no connection available. It returns with 'no connection' return value in this case.
+
Next some example source for common tasks found in usual sending functionality:
Next some example source for common tasks found in usual sending functionality:
 +
==== Example sending loop ====
==== Example sending loop ====
-
When you process SharingEntryMedias from the SharingEntry you propably end up with loop where you go the list of SharingEntryMedias through. Here is a raw example, where some example lines commented out with "//".
+
When you process <code>SharingEntryMedia</code>s from the <code>SharingEntry</code> you propably end up with loop where you go the list of SharingEntryMedias through. Here is a raw example, where some example lines commented out with "//".
-
<tt>
+
-
for (GSList* p = sharing_entry_get_media (entry); p != NULL; p = g_slist_next(p)) {
+
<source lang="c">
-
    SharingEntryMedia* media = p->data;
+
for (GSList* p = sharing_entry_get_media (entry); p != NULL; p = g_slist_next(p)) {
-
    /* Process media */
+
  SharingEntryMedia* media = p->data;
-
    if (!sharing_entry_media_get_sent (media)) {
+
  /* Process media */
-
        /* Post media */
+
  if (!sharing_entry_media_get_sent (media)) {
-
        //guint result = my_send_task_post_function (my_send_task, media);
+
      /* Post media */
-
        /* Process post result */
+
      //guint result = my_send_task_post_function (my_send_task, media);
-
        if (result == 0 /* EXAMPLE: MY_SEND_RESULT_SUCCESS */) {
+
      /* Process post result */
-
            /* If success mark media as sent */
+
      if (result == 0 /* EXAMPLE: MY_SEND_RESULT_SUCCESS */) {
-
            sharing_entry_media_set_sent (media, TRUE);
+
          /* If success mark media as sent */
-
            /* And mark process to your internal data structure */
+
          sharing_entry_media_set_sent (media, TRUE);
-
            //my_send_task->upload_done += sharing_entry_media_get_size (media);  
+
          /* And mark process to your internal data structure */
-
        } else {
+
          //my_send_task->upload_done += sharing_entry_media_get_size (media);  
-
            /* We have sent the file in last sharing-manager call */
+
      } else {
-
            //my_send_task->upload_done += sharing_entry_media_get_size (media);
+
          /* We have sent the file in last sharing-manager call */
-
        }
+
          //my_send_task->upload_done += sharing_entry_media_get_size (media);
-
    }
+
      }
-
}
+
  }
 +
}
 +
</source>
-
</tt>
+
==== Example tags string ====
-
==== Example tags string ====
 
Usually services accept the tags in their API to be added to images. Here is example source to create nice string about tag information to be put  where ", " string used as separator. If service supports also geo tagging you should develop this source further by checking the tag type also.
Usually services accept the tags in their API to be added to images. Here is example source to create nice string about tag information to be put  where ", " string used as separator. If service supports also geo tagging you should develop this source further by checking the tag type also.
-
<tt>
 
-
static gchar* create_tags_str (const GSList* tags)
+
<source lang="c">
-
{
+
static gchar* create_tags_str (const GSList* tags)
-
    gchar* ret = NULL;
+
{
-
    for (const GSList* p = tags; p != NULL; p = g_slist_next (p)) {
+
  gchar* ret = NULL;
-
        SharingTag* tag = (SharingTag*)(p->data);
+
  for (const GSList* p = tags; p != NULL; p = g_slist_next (p)) {
-
        const gchar* tmp = sharing_tag_get_word (tag);
+
      SharingTag* tag = (SharingTag*)(p->data);
-
        if (tmp != NULL) {
+
      const gchar* tmp = sharing_tag_get_word (tag);
-
            gchar* new_ret = NULL;
+
      if (tmp != NULL) {
-
            if (ret != NULL) {
+
          gchar* new_ret = NULL;
-
                new_ret = g_strdup_printf ("%s, %s", ret, tmp);
+
          if (ret != NULL) {
-
                g_free (ret); /* old return is freed */
+
              new_ret = g_strdup_printf ("%s, %s", ret, tmp);
-
            } else {
+
              g_free (ret); /* old return is freed */
-
                new_ret = g_strdup (tmp);
+
          } else {
-
            }
+
              new_ret = g_strdup (tmp);
-
            ret = new_ret;
+
          }
-
        }
+
          ret = new_ret;
-
    }
+
      }
-
    return ret;
+
  }
-
}
+
  return ret;
-
gchar* tags = create_tags_str (sharing_entry_media_get_tags (media));
+
}
-
</tt>
+
gchar* tags = create_tags_str (sharing_entry_media_get_tags (media));
 +
</source>
==== SharingHTTP example ====
==== SharingHTTP example ====
-
SharingHTTP is ment to be used for HTTP transfers. It is probably easier to use this than libcurl and libconic straightly in common cases. Give it a try at least if you are not familiar with libcurl!
 
-
<tt>
+
<code>SharingHTTP</code> is meant to be used for HTTP transfers. It is probably easier to use this than libcurl and libconic directly in common cases. Give it a try at least if you are not familiar with libcurl!
-
SharingHTTP * http = sharing_http_new ();
+
 
-
SharingHTTPRunResponse res;
+
<source lang="c">
-
res = sharing_http_run (http, "http://example.com/post");
+
SharingHTTP * http = sharing_http_new ();
-
if (res == SHARING_HTTP_RUNRES_SUCCESS) {
+
SharingHTTPRunResponse res;
-
  g_print ("Got response (%d): %s\n", sharing_http_get_res_code (http),
+
res = sharing_http_run (http, "http://example.com/post");
-
    sharing_http_get_res_body (http, NULL));
+
if (res == SHARING_HTTP_RUNRES_SUCCESS) {
-
} else {
+
g_print ("Got response (%d): %s\n", sharing_http_get_res_code (http),
-
    g_printerr ("Couldn't get stuff from service\n");
+
    sharing_http_get_res_body (http, NULL));
-
}
+
} else {
-
sharing_http_unref (http);  
+
    g_printerr ("Couldn't get stuff from service\n");
-
</tt>
+
}
 +
sharing_http_unref (http);  
 +
</source>
===Update options===
===Update options===
-
sharing_plugin_interface_update_options is used to udpate account specific
+
 
 +
<code>sharing_plugin_interface_update_options</code> is used to update account specific
options in Sharing Dialog's Options menu. This is pretty handy when you want to have
options in Sharing Dialog's Options menu. This is pretty handy when you want to have
changing options in your plug-in for example albums.
changing options in your plug-in for example albums.
Line 356: Line 389:
You are defining these options in your plug-in's service definion .xml file. For
You are defining these options in your plug-in's service definion .xml file. For
example next lines can add updatable option "album" to the plug-in's accounts:
example next lines can add updatable option "album" to the plug-in's accounts:
-
    <option id="album" type="updatable" default="default_photoset">
+
<source lang="xml">
-
        <caption domain="osso-sharing-ui" key="share_ti_select_album"/>
+
<option id="album" type="updatable" default="default_photoset">
-
        <value id="default_photoset" domain="osso-sharing-ui" key="Default"/>
+
    <caption domain="osso-sharing-ui" key="share_ti_select_album"/>
-
    </option>
+
    <value id="default_photoset" domain="osso-sharing-ui" key="Default"/>
 +
</option>
 +
</source>
-
When update options is pressed sharing_plugin_interface_update_options is called.
+
When update options is pressed <code>sharing_plugin_interface_update_options</code> is called. After you have got the newest options from service's server you can add them to currently selected account by creating a <code>GSList*</code> of <code>SharingServiceOptionValues</code>. After having a nice list of new options you can then set them to account with <code>sharing_account_set_option_values (self->account, "album", option_values)</code>.
-
After you have got the newest options from service's server you can add them
+
-
to currently selected account by creating a GSList* of SharingServiceOptionValues.
+
-
After having a nice list of new options you can then set them to account with
+
-
sharing_account_set_option_values (self->account, "album", option_values).
+
-
When setting the options to account is done you have to call the function that was
+
When setting the options to account is done you have to call the function that was given to you as parameter passing the <code>SharingPluginInterfaceUpdateOptionsResult</code> with value of your choise and the already before got <code>cb_data</code> as parameter. This tells to the caller that your part from the update flow is succesfully done. Next source can be used to create this function call (self->result is containing the result in you opinion):
-
given to you as parameter passing the SharingPluginInterfaceUpdateOptionsResult
+
-
with value of your choise and the already before got cb_data as parameter.
+
-
This tells to the caller that your part from the update flow is succesfully done.
+
-
Next source can be used to create this function call (self->result is containing
+
-
the result in you opinion):
+
-
    /* Callback */
+
<source lang="c">
-
    if (self->cb_func != NULL) {
+
/* Callback */
-
        void (*fp) (SharingPluginInterfaceUpdateOptionsResult, gpointer);
+
if (self->cb_func != NULL) {
-
        fp = self->cb_func;
+
    void (*fp) (SharingPluginInterfaceUpdateOptionsResult, gpointer);
-
        fp (self->result, self->cb_data);
+
    fp = self->cb_func;
-
    } else {
+
    fp (self->result, self->cb_data);
-
        ; /* Fail */
+
} else {
-
    }
+
    ; /* Fail */
 +
}
 +
</source>
You can have the callback function and it's parameter stored for example in  
You can have the callback function and it's parameter stored for example in  
next form:
next form:
-
    void (*cb_func)(UpdateOptionsCallback result, gpointer data);
+
 
-
    gpointer cb_data;
+
<source lang="c">
 +
void (*cb_func)(UpdateOptionsCallback result, gpointer data);
 +
gpointer cb_data;
 +
</source>
===Uninstallation===
===Uninstallation===
-
Libsharing provides sharing-account-remover binary that can be used to clean Sharing Accounts created for your plugin. This binary is run by debian/ dir's prerm script. Prerm scripts are run just before the package is uninstalled. Change the plugin id from sharingplugintemplate to match your plug-in id in the script. Your plug-in's id is the service definitions files prefix. For template.service.xml, the prefix is "template".
+
 
 +
Libsharing provides the <code>sharing-account-remover</code> binary that can be used to clean Sharing Accounts created for your plugin. This binary is run by debian/ dir's prerm script. Prerm scripts are run just before the package is uninstalled. Change the plugin id from <code>sharingplugintemplate</code> to match your plug-in id in the script. Your plug-in's id is the service definitions files prefix. For template.service.xml, the prefix is "template".
Example prerm script:
Example prerm script:
-
<tt>
+
<source lang="bash">
-
#!/bin/sh
+
#!/bin/sh
-
# You can use sharing-account-remover to remove the accounts at plugin
+
# You can use sharing-account-remover to remove the accounts at plugin
-
# uninstallation
+
# uninstallation
-
if [ "$1" = "remove" ]; then
+
if [ "$1" = "remove" ]; then
-
/usr/bin/sharing-account-remover <service name>
+
/usr/bin/sharing-account-remover <service name>
-
fi
+
fi
-
</tt>
+
</source>
==Testing your plugin==
==Testing your plugin==
-
After setting up your scratchbox environment you can start using and testing your own plugin.  
+
 
 +
After setting up your Scratchbox environment you can start using and testing your own plugin.  
Sharing framework consists following packages:
Sharing framework consists following packages:
Line 429: Line 462:
==Sharing your plugin with others==
==Sharing your plugin with others==
 +
Maemo Extras repository is the best place for your plug-in if you want to get users for it. More information on how you can [[Uploading to Extras-devel|upload packages to Extras repository]] is available.
Maemo Extras repository is the best place for your plug-in if you want to get users for it. More information on how you can [[Uploading to Extras-devel|upload packages to Extras repository]] is available.
-
Before uploading plugin to public repositories make sure you have updated the debian configuration files to match your information under ./debian folder.
+
Before uploading plugin to public repositories make sure you have updated the Debian configuration files to match your information under ./debian folder.
-
Also make sure that the section is set to [[Documentation/Maemo 5 Developer Guide/Packaging, Deploying and Distributing#Sections | one of the valid sections listed in the packaging guide]]. For data sharing, use "user/multimedia". This way the package will be installable by application manager. Below example version of debian control file.
+
Also make sure that the section is set to [[Documentation/Maemo 5 Developer Guide/Packaging, Deploying and Distributing#Sections|one of the valid sections listed in the packaging guide]]. For data sharing, use <code>user/multimedia</code>. This way the package will be installable by application manager. Below example version of debian control file.
  Source: sharing-plugin-template
  Source: sharing-plugin-template

Latest revision as of 15:28, 10 August 2010

With the Sharing dialog API, the user can open the first dialog, which starts the Sharing flow. From the first dialog the user can select "Send via Bluetooth", "Send via E-mail" and "Share via service".

More detailed API documentation can be found from here.

Example code how to use the API:

/* create osso context in your app that is passed to sharing */
osso_context_t *osso = osso_initialize ("my_app", "1.0.0.", FALSE, NULL);
/* file to open */
gchar *filename = "/path/to/file";
sharing_dialog_with_file (osso,
                          GTK_WINDOW (parent),
                          filename);

In the example above we use the API to start sharing single file. In case you want to share simultaneously more than one file or you want to change what button are seen in the dialog use one of the functions below.

 void sharing_dialog_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris);
 void sharing_dialog_button_mask_with_file (osso_context_t * osso, GtkWindow * parent, const gchar * uris, guint share_button_mask);
 void sharing_dialog_button_mask_with_files (osso_context_t * osso, GtkWindow * parent, GSList * uris, guint share_button_mask);

Contents

[edit] Compiling

When compiling your application use the following pkg-config configuration:

`pkg-config --cflags --libs sharingdialog`

[edit] Writing "Send Via" Functionality for E-mail and Bluetooth

Send Via E-mail and Bluetooth can be used directly without Sharing dialog and the functionality is provided by the platform to enable applications to send data via E-mail or over a Bluetooth connection. Because several applications share this functionality, the platform provides a public interface to facilitate the deployment of these services in user applications. The interfaces are defined in two header files: libmodest-dbus-client.h (in the libmodest-dbus-client-dev package) and conbtdialogs-dbus.h (in the conbtdialogs-dev package). The following sample code is an example of the usage of these interfaces. See the maemopad source code available in the SDK repository for a fully functional application using this service.

maemopad/src/maemopad-window.c

/* send via email: */
#include <libmodest-dbus-client/libmodest-dbus-client.h>
/* send via bt: */
#include <conbtdialogs-dbus.h>
/*......*/
static void maemopad_window_on_menu_sendvia_email (GtkButton *button, gpointer data)
{
 MaemopadWindow *self = MAEMOPAD_WINDOW (data);
 gboolean result = TRUE;
 GSList *list = NULL;
 g_assert (self);
 /* Attach the saved file (and not the one currently on screen). If the file 
  * has not been saved yet, nothing is attached */
 if (self->file_name) {
  list = g_slist_append(list, self->file_name);
  result = libmodest_dbus_client_compose_mail(self->osso, /*osso_context_t*/
    NULL, /*to*/
    NULL, /*cc*/
    NULL, /*bcc*/
    NULL, /*body*/
    NULL, /*subject*/
    list /*attachments*/);
 }
 g_slist_free(list);
 if (result == FALSE)
  g_print("Could not send via email\n");
}
 
static gboolean maemopad_window_rpc_sendvia_bluetooth (const gchar *path)
{
 DBusGProxy *proxy = NULL;
 DBusGConnection *sys_conn = NULL;
 GError *error = NULL;
 gboolean result = TRUE;
 gchar **files = NULL;
 /*sys_conn = osso_get_sys_dbus_connection(ctx);*/
 sys_conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
 if(sys_conn == NULL)
 {
  return FALSE;
 }
 files = g_new0(gchar*, 2);
 *files = g_strdup(path);
 files[1] = NULL;
 /* Open connection for btdialogs service */
 proxy = dbus_g_proxy_new_for_name(sys_conn,
  CONBTDIALOGS_DBUS_SERVICE,
  CONBTDIALOGS_DBUS_PATH,
  CONBTDIALOGS_DBUS_INTERFACE);
 /* Send send file request to btdialogs service */
 if (!dbus_g_proxy_call(proxy, CONBTDIALOGS_SEND_FILE_REQ,
  &error, G_TYPE_STRV, files,
  G_TYPE_INVALID, G_TYPE_INVALID))
 {
  g_print("Error: %s\n", error->message);
  g_clear_error (&error);
  result = FALSE;
 }
 g_strfreev(files);
 g_object_unref(proxy);
 return result;
}

[edit] Writing Sharing Plug-in for "Send via Service"

Maemo 5 introduces a new library for handling Sharing related information and services. This chapter will walk you through the process of creating a sharing plug-in using a template plug-in as example. Basic knowledge of Debian development and working in a Scratchbox environment is needed in order to follow these guides.

Plugin template with some example codes is located here Data Sharing Plugin example

Detailed API documentation is available in libsharing-plugin-doc package in gtk-doc format.

Before starting to create your own plugin it is a good idea to check the default services: OVI and Flickr. From those you can see two different UI flows for creating accounts. In OVI the UI flow is pretty simple and clear, you just type a user name and password and then validate the account. In Flickr the flow is more complex, as before validation the user must login to Flickr via a web page to get authentication and continue the validation after that.

Account creation is started from Settings:

Settings -> Sharing accounts -> New -> Select service ...

[edit] Sharing User Interfaces

Sharing application abstracts the file sharing and implements common parts needed for file sharing application. Sharing Application service support can be extended by using Sharing Plug-ins. These plug-ins can be created by any 3rd party developer. The plug-ins should implement the Sharing Plug-in API functions and define some parameters in a service definition XML file.

Figure 1 below shows Sharing accounts dialog opened from the control panel. With the Sharing accounts, you can create a new Sharing account or edit an existing one. If you install a custom Sharing plug-in, you can see the service it provides in the "Select service list" when creating a new Sharing account.


Image:SharingAccounts.png

Figure 1: Sharing Accounts


Figure 2 shows the Sharing Dialog user interface that is used to share images with the selected account on some service. The images displayed can come for example from the Photos application or from the device camera. You can choose the account created for your service from the "Account" combo box which holds all existing Sharing accounts.

Image:SharingDialogInterface.png

Figure 2: Sharing Dialog User Interface

[edit] Getting Familiar With Target Service API

Many web services provide APIs that are available for 3rd party developers. In this tutorial, we focus on services that provide APIs for image and video uploads. It is possible to give a title, description and tags for the images using the common service API. Sharing supports image scaling and metadata filtering as common options for any service. Sharing Plug-ins can have service-specific options, like privacy. These settings can be accessed through the Options dialog (in Figure 2.)

[edit] Getting Your Dummy Plugin To Sharing Menus

As a prerequisite, you will need a working Maemo 5 SDK to continue further. We will first install the Sharing Plug-in template:

  • Obtain the template source code sharing-plugin-template-0.1.tar.gz from the maemoexamples repository. It contains a good start up file structure for creating a plugin.
  • Extract and build the package from the folder using command:
./autogen.sh; dpkg-buildpackage -rfakeroot -d
  • Install the package built for your Scratchbox environment or to the device if it was built with the ARM target.
  • The template dummy service should be now visible in the Sharing account when creating new accounts.
Image:Ambox_notice.png
Note that this template plugin does not send any data before you write the implementation for it.

[edit] Editing Template Plug-in

In this section, we peek under the hood by opening the files found from the template plugin and get familiar with Sharing classes that are used in the Sharing Plugin API functions.

[edit] Sharing Internals

Figure 3 shows the general overview of how Sharing Plug-in connects to Sharing Application using the Sharing Plugin API. The basic plug-in components are the service definition file and the plugin library. The Application Sharing-Dialog is used to create SharingEntries that are shared by a SharingManager. Sharing Account Manager implements the Sharing Accounts. Libsharing is a library for all common Sharing functionality.

Image:SharingPluginAPI.jpg

Figure 3: Sharing Plugin API


Figure 4 shows the common Sharing classes found in libsharing that you would use while creating the plug-in:

  • SharingTransfer is the object that contains all the data of a sharing task, overall status of the transfer process for one set of shared files.
  • SharingEntry contains the SharingEntryMedia that are the selected files. It also knows the SharingAccount that is the target of sharing.
  • SharingAccount contains the username and password along with other parameters that you have to save for your service's accounts. It also has the information about SharingService which is registered with the SharingAccount.

Image:LibSharingClasses.jpg

Figure 4: Libsharing classes

To see more detail the sharing classes you can browse to Sharing plugin example

[edit] Service XML File

The service definition file, data/template.service.xml.in is the starting point for plugin loading. It defines the library that implements Sharing Plugin API functions, the sign up URL for totally new account creation using a web browser, the service name, icon file names and some basic information from plug-in.

<?xml version="1.0" encoding="UTF-8"?> 
<service plugin="libtemplate.so" provider="Me"> 
 
   <accounts plugInSetup="0" plugInEdit="0">
     <signup>www.maemo.org</signup> 
     <password maxlen="32"/> 
   </accounts> 
 
   <ui> 
       <name>Template</name>  
       <icon type="post">@servicesdir@/template-post.png</icon> 
       <icon type="setup">@servicesdir@/template-setup.png</icon> 
       <options> 
           <option id="privacy" type="enumeration" default="private"> 
               <caption domain="osso-sharing-ui" key="share_bd_options_privacy"/> 
               <value id="private" domain="osso-sharing-ui" key="share_fi_options_privacy_private"/> 
               <value id="public" domain="osso-sharing-ui" key="share_fi_options_privacy_public"/>
               </option>
       </options>
    </ui>
</service>

File 1: Example service definition XML file

[edit] How to read the xml file

The prefix of the xml file name defines the used service id of the plugin. In our example the id is "template".

Service element:

<service plugin="" provider="">
...
</service>
  • Service is the root node of each service xml and must be named exactly service.
  • Property plugin defines the library name that Sharing will look for in /usr/lib/sharing.
  • Property provider defines the plugin provider.

Accounts element:

<accounts plugInSetup="0" plugInEdit="0">
  <signup>www.myservicepage.com</signup> 
</accounts>
  • Accounts element defines the account setup options.
  • Property plugInSetup defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
  • Property plugInEdit defines if sharing should use internal default flow or flow implemented in the plugin itself. Set to "1" in case using own flow.
  • Element signup defines the URL where browser is opened in case default flow used when user press button "Register new account" in account setup dialog.

Ui element:

<ui> 
  <name>...</name>  
  <icon type="post">@servicesdir@/...</icon> 
  <icon type="setup">@servicesdir@/...</icon> 
  <options> 
    ...
  </option>
</ui>
  • UI element defines Name, icons and options that can be modified through XML file.
  • Element name defines the name that is shown for the service in all the UI.
  • Element icon defines the used icons. Property post or setup can be used. Property setup defines the icon shown in account setup dialogs.
  • Element options defines the different changeable options for selected service. See more below.

Options element:

<options>
  <option id="..." type="enumeration || updatable" default="..."> 
    <caption domain="osso-sharing-ui" key="..."/> 
    <value id="..." domain="osso-sharing-ui" key="..."/> 
  </option>
  <option>
  ...
  </option>
</options>
  • Options element defines all the options that a user can change through "Options" for the selected service. Each individual option is an element option.
  • Property id defines the internal id for this option. User selected choice for this option is asked with the id, see here.
  • Property type defines the type of option. You can select enumeration or updatable. For the enumeration you need to specify the shown values with values elements. Updatable option can contain default values and the remaining values can be updated from service.
  • Property default defines the default value to select if user haven't made any selections yet. The value of the default property must mach one of the value element ids.
  • Properties domain and key under caption element defines the actual text to be displayed. If you want to use some localization package then define domain and desired logical id to key. For free text the domain is not mandatory.
  • Element value defines one value in the selection. If option is updatable new values with id/key pair can be added in code, see here. Otherwise you need to specify the shown values.

[edit] Account Setup User Interface Flow

Sharing accounts can either create a default flow where username and password parameters are set to the account or an optional custom flow. In File 1, the accounts tag has a parameter plugInSetup. If it is set to "1", Sharing Accounts will call the Sharing Plugin API function sharing_plugin_interface_account_setup to create UI flow; it will use the default flow. You can see the difference between UI flows when creating Flickr and Ovi account. Ovi uses the default flow and Flickr uses it's own UI flow.

SharingPluginInterfaceAccountSetupResult sharing_plugin_interface_account_setup (GtkWindow* parent, SharingService* service, SharingAccount** worked_on, osso_context_t* osso)

If you decide to create your own account setup flow, please try to keep the same UI look as in other Sharing dialogs.

[edit] Account Validation

Account validation is needed to reduce error cases in the sending process. Of course you can use the dummy function at template plug-in, but for better user experience this function is recommended to be implemented so that Sharing Account account information is really validated against the service when new account is created.

Next function is called after sharing_plugin_interface_account_setup call ends or when default account setup flow is done (when the "Validate" button is pressed).

SharingPluginInterfaceAccountValidateResult sharing_plugin_interface_account_validate (SharingAccount* account, ConIcConnection* con, gboolean *cont, gboolean* dead_mans_switch)

In the last phase of account creation, the account must be validated. Sharing Plug-in API sharing_plugin_interface_test_account is the function called in the validation phase of the account creation flow. Usually web services have a phase in account creation where you have put the needed information from your account, only then you get the actual credentials to upload images if your account information is valid. This is the phase that is implemented in the Sharing Plug-in API function.

[edit] Account Editing User Interface Flow

Sharing Accounts support here too either default flow where username and password parameters are edited or optional custom edit UI flow. The desired flow can be set by setting the parameter plugInEdit from the service definition file either to "0" or to "1" where "0" means the default flow and "1" plug-in flow.

The default flow can be used when you need only username and password to get needed information for sending. The plug-in flow is used when you need more than this or customised account validation flow. You can see the difference between UI flows here too when editing Flickr and Ovi accounts.

Next function must be implemented only when plug-in account setup is used (when plugInSetup is set to "1"):

SharingPluginInterfaceEditAccountResult sharing_plugin_interface_edit_account (GtkWindow* parent, SharingAccount* account, ConIcConnection* con, gboolean* dead_mans_switch)

[edit] Sending Functionality

SharingPluginInterfaceSendResult sharing_plugin_interface_send (SharingTransfer* transfer, ConIcConnection* con, gboolean* dead_mans_switch)

After pressing the 'Share' button in Sharing dialog (Figure 2.), the data is put into the Sharing Outbox (can be seen under /home/user/MyDocs/.sharing/outbox/). Sharing manager process is started and the status menu gets the icon to process the new Sharing Entry. SharingHTTP provides an API to create common HTTP requests. In order to create a better user experience following things are good to be implemented after you get the basic functionality working in your plug-in:

  • Set progress of sending with sharing_transfer_set_progress between 0 and 1 to estimate the current transfer time / total transfer time.
  • Set sent to SharingEntryMedia with sharing_entry_media_set_sent when file sending is done and check the send value with sharing_entry_media_get_sent to prevent sending same files multiple times for example in reboot scenarios.
  • Poll cancel flag time to time, for example in curl or SharingHTTP progress function to end transferring when needed. Use sharing_transfer_continue to get the continue flag bit.
  • If you are using libcurl instead of SharingHTTP, please listen to conic events to disconnect transfer when no connection available. It returns with 'no connection' return value in this case.

Next some example source for common tasks found in usual sending functionality:

[edit] Example sending loop

When you process SharingEntryMedias from the SharingEntry you propably end up with loop where you go the list of SharingEntryMedias through. Here is a raw example, where some example lines commented out with "//".

for (GSList* p = sharing_entry_get_media (entry); p != NULL; p = g_slist_next(p)) {
   SharingEntryMedia* media = p->data;
   /* Process media */
   if (!sharing_entry_media_get_sent (media)) {
       /* Post media */
       //guint result = my_send_task_post_function (my_send_task, media);
       /* Process post result */
       if (result == 0 /* EXAMPLE: MY_SEND_RESULT_SUCCESS */) {
           /* If success mark media as sent */
           sharing_entry_media_set_sent (media, TRUE);
           /* And mark process to your internal data structure */
           //my_send_task->upload_done += sharing_entry_media_get_size (media); 
       } else {
           /* We have sent the file in last sharing-manager call */
           //my_send_task->upload_done += sharing_entry_media_get_size (media);
       }
   }
}

[edit] Example tags string

Usually services accept the tags in their API to be added to images. Here is example source to create nice string about tag information to be put where ", " string used as separator. If service supports also geo tagging you should develop this source further by checking the tag type also.

static gchar* create_tags_str (const GSList* tags)
{
   gchar* ret = NULL;
   for (const GSList* p = tags; p != NULL; p = g_slist_next (p)) {
       SharingTag* tag = (SharingTag*)(p->data);
       const gchar* tmp = sharing_tag_get_word (tag);
       if (tmp != NULL) {
           gchar* new_ret = NULL;
           if (ret != NULL) {
               new_ret = g_strdup_printf ("%s, %s", ret, tmp);
               g_free (ret); /* old return is freed */
           } else {
               new_ret = g_strdup (tmp);
           }
           ret = new_ret;
       }
   }
   return ret;
}
gchar* tags = create_tags_str (sharing_entry_media_get_tags (media));

[edit] SharingHTTP example

SharingHTTP is meant to be used for HTTP transfers. It is probably easier to use this than libcurl and libconic directly in common cases. Give it a try at least if you are not familiar with libcurl!

SharingHTTP * http = sharing_http_new ();
SharingHTTPRunResponse res;
res = sharing_http_run (http, "http://example.com/post");
if (res == SHARING_HTTP_RUNRES_SUCCESS) {
 g_print ("Got response (%d): %s\n", sharing_http_get_res_code (http),
    sharing_http_get_res_body (http, NULL));
} else {
    g_printerr ("Couldn't get stuff from service\n");
}
sharing_http_unref (http);

[edit] Update options

sharing_plugin_interface_update_options is used to update account specific options in Sharing Dialog's Options menu. This is pretty handy when you want to have changing options in your plug-in for example albums.

You are defining these options in your plug-in's service definion .xml file. For example next lines can add updatable option "album" to the plug-in's accounts:

<option id="album" type="updatable" default="default_photoset">
    <caption domain="osso-sharing-ui" key="share_ti_select_album"/>
    <value id="default_photoset" domain="osso-sharing-ui" key="Default"/>
</option>

When update options is pressed sharing_plugin_interface_update_options is called. After you have got the newest options from service's server you can add them to currently selected account by creating a GSList* of SharingServiceOptionValues. After having a nice list of new options you can then set them to account with sharing_account_set_option_values (self->account, "album", option_values).

When setting the options to account is done you have to call the function that was given to you as parameter passing the SharingPluginInterfaceUpdateOptionsResult with value of your choise and the already before got cb_data as parameter. This tells to the caller that your part from the update flow is succesfully done. Next source can be used to create this function call (self->result is containing the result in you opinion):

/* Callback */
if (self->cb_func != NULL) {
    void (*fp) (SharingPluginInterfaceUpdateOptionsResult, gpointer);
    fp = self->cb_func;
    fp (self->result, self->cb_data);
} else {
    ; /* Fail */
}

You can have the callback function and it's parameter stored for example in next form:

void (*cb_func)(UpdateOptionsCallback result, gpointer data);
gpointer cb_data;

[edit] Uninstallation

Libsharing provides the sharing-account-remover binary that can be used to clean Sharing Accounts created for your plugin. This binary is run by debian/ dir's prerm script. Prerm scripts are run just before the package is uninstalled. Change the plugin id from sharingplugintemplate to match your plug-in id in the script. Your plug-in's id is the service definitions files prefix. For template.service.xml, the prefix is "template".

Example prerm script:

#!/bin/sh
# You can use sharing-account-remover to remove the accounts at plugin
# uninstallation
if [ "$1" = "remove" ]; then
	/usr/bin/sharing-account-remover <service name>
fi

[edit] Testing your plugin

After setting up your Scratchbox environment you can start using and testing your own plugin.

Sharing framework consists following packages:

libsharing-plugin-dev
libsharing0
sharing-manager
sharing-account-manager
sharing-dialog
sharing-service-ovi
sharing-service-flickr

All the needed packages should be installed along with nokia-binaries.

Important: When testing inside scratchbox remember to start the signond daemon after the desktop is started. Signond is used for storing the account information and it's needed in order to get Sharing framework working properly

[sbox] > signond &

Also remember to install the debian .deb package build from your sources.

Creating sharing account is started from setting.

settings -> Sharing accounts -> New

Select your service and create new account. After one account is created you can use ImageViewer for sharing images and MediaPlayer for sharing video files.

[edit] Sharing your plugin with others

Maemo Extras repository is the best place for your plug-in if you want to get users for it. More information on how you can upload packages to Extras repository is available.

Before uploading plugin to public repositories make sure you have updated the Debian configuration files to match your information under ./debian folder.

Also make sure that the section is set to one of the valid sections listed in the packaging guide. For data sharing, use user/multimedia. This way the package will be installable by application manager. Below example version of debian control file.

Source: sharing-plugin-template
Section: user/multimedia
Priority: optional
Maintainer: Maemo Team <xxxx@maemo.org>
Build-Depends: debhelper (>= 5.0.0), 
   libgtk2.0-dev, libglib2.0-dev, 
   libconic0-dev, libosso-dev, 
   libsharing-plugin-dev
Standards-Version: 3.8.0