[Telepathy-commits] [telepathy-gabble/master] Re-implement activity views using the new API

Guillaume Desmottes guillaume.desmottes at collabora.co.uk
Thu Oct 16 03:19:07 PDT 2008


---
 src/Makefile.am                            |    2 +
 src/conn-olpc.c                            |  463 +++------------------------
 src/conn-olpc.h                            |    3 +
 src/olpc-activity-view.c                   |  473 ++++++++++++++++++++++++++++
 src/olpc-activity-view.h                   |   71 +++++
 src/olpc-gadget-manager.c                  |  179 +++++++++++-
 src/olpc-gadget-manager.h                  |    4 +
 tests/twisted/olpc/olpc-activity-search.py |  150 +++++++---
 tests/twisted/olpc/util.py                 |   14 +-
 9 files changed, 902 insertions(+), 457 deletions(-)
 create mode 100644 src/olpc-activity-view.c
 create mode 100644 src/olpc-activity-view.h

diff --git a/src/Makefile.am b/src/Makefile.am
index a29e571..8d7cab9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -71,6 +71,8 @@ libgabble_convenience_la_SOURCES = \
     namespaces.h \
     olpc-activity.h \
     olpc-activity.c \
+    olpc-activity-view.h \
+    olpc-activity-view.c \
     olpc-buddy-view.h \
     olpc-buddy-view.c \
     olpc-gadget-manager.h \
diff --git a/src/conn-olpc.c b/src/conn-olpc.c
index 8b6144f..818d732 100644
--- a/src/conn-olpc.c
+++ b/src/conn-olpc.c
@@ -420,33 +420,6 @@ get_properties_reply_cb (GabbleConnection *conn,
   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
 }
 
-#if 0
-static gboolean
-find_view_having_properties_for_buddy (gpointer id,
-                                       gpointer value,
-                                       gpointer buddy)
-{
-  GabbleOlpcView *view = GABBLE_OLPC_VIEW (value);
-  TpHandle handle = GPOINTER_TO_UINT (buddy);
-
-  return gabble_olpc_view_get_buddy_properties (view, handle) != NULL;
-}
-
-static GHashTable *
-find_buddy_properties_from_views (GabbleConnection *conn,
-                                  TpHandle buddy)
-{
-  GabbleOlpcView *view;
-
-  view = g_hash_table_find (conn->olpc_views,
-      find_view_having_properties_for_buddy, GUINT_TO_POINTER (buddy));
-  if (view == NULL)
-    return NULL;
-
-  return gabble_olpc_view_get_buddy_properties (view, buddy);
-}
-#endif
-
 static void
 olpc_buddy_info_get_properties (GabbleSvcOLPCBuddyInfo *iface,
                                 guint contact,
@@ -916,85 +889,6 @@ check_activity_properties (GabbleConnection *conn,
     }
 }
 
-#if 0
-struct find_activities_of_buddy_ctx
-{
-  TpHandle buddy;
-  GHashTable *activities;
-};
-
-static void
-find_activities_of_buddy (TpHandle contact,
-                          GabbleOlpcView *view,
-                          struct find_activities_of_buddy_ctx *ctx)
-{
-  GPtrArray *act;
-  guint i;
-
-  act = gabble_olpc_view_get_buddy_activities (view, ctx->buddy);
-
-  for (i = 0; i < act->len; i++)
-    {
-      GabbleOlpcActivity *activity;
-
-      activity = g_ptr_array_index (act, i);
-      g_hash_table_insert (ctx->activities, GUINT_TO_POINTER (activity->room),
-          activity);
-    }
-
-  g_ptr_array_free (act, TRUE);
-}
-
-static void
-copy_activity_to_array (TpHandle room,
-                        GabbleOlpcActivity *activity,
-                        GPtrArray *activities)
-{
-  GValue gvalue = { 0 };
-
-  if (activity->id == NULL)
-  {
-    DEBUG ("... activity #%u has no ID, skipping", room);
-    return;
-  }
-
-  g_value_init (&gvalue, GABBLE_STRUCT_TYPE_ACTIVITY);
-  g_value_take_boxed (&gvalue, dbus_g_type_specialized_construct
-      (GABBLE_STRUCT_TYPE_ACTIVITY));
-  dbus_g_type_struct_set (&gvalue,
-      0, activity->id,
-      1, activity->room,
-      G_MAXUINT);
-  DEBUG ("... activity #%u (ID %s)",
-      activity->room, activity->id);
-  g_ptr_array_add (activities, g_value_get_boxed (&gvalue));
-}
-
-static GPtrArray *
-find_buddy_activities_from_views (GabbleConnection *conn,
-                                  TpHandle contact)
-{
-  GPtrArray *result;
-  struct find_activities_of_buddy_ctx ctx;
-
-  result = g_ptr_array_new ();
-
-  /* We use a hash table first so we won't add twice the same activity */
-  ctx.activities = g_hash_table_new (g_direct_hash, g_direct_equal);
-  ctx.buddy = contact;
-
-  g_hash_table_foreach (conn->olpc_views, (GHFunc) find_activities_of_buddy,
-      &ctx);
-
-  /* Now compute the result array using the hash table */
-  g_hash_table_foreach (ctx.activities, (GHFunc) copy_activity_to_array,
-      result);
-
-  g_hash_table_destroy (ctx.activities);
-
-  return result;
-}
-
 static void
 return_buddy_activities_from_views (GabbleConnection *conn,
                                     TpHandle contact,
@@ -1002,12 +896,12 @@ return_buddy_activities_from_views (GabbleConnection *conn,
 {
   GPtrArray *activities;
 
-  activities = find_buddy_activities_from_views (conn, contact);
+  activities = gabble_olpc_gadget_manager_find_buddy_activities (
+      conn->olpc_gadget_manager, contact);
   gabble_svc_olpc_buddy_info_return_from_get_activities (context, activities);
 
   free_activities (activities);
 }
-#endif
 
 static LmHandlerResult
 get_activities_reply_cb (GabbleConnection *conn,
@@ -1045,10 +939,8 @@ get_activities_reply_cb (GabbleConnection *conn,
 
   if (lm_message_get_sub_type (reply_msg) != LM_MESSAGE_SUB_TYPE_RESULT)
     {
-#if 0
       DEBUG ("Failed to query PEP node. Compute activities list using views");
       return_buddy_activities_from_views (conn, from_handle, context);
-#endif
       return LM_HANDLER_RESULT_REMOVE_MESSAGE;
     }
 
@@ -2999,7 +2891,6 @@ buddy_changed (GabbleConnection *conn,
     }
 }
 
-#if 0
 static void
 activity_changed (GabbleConnection *conn,
                   LmMessageNode *change)
@@ -3023,7 +2914,6 @@ activity_changed (GabbleConnection *conn,
         }
     }
 }
-#endif
 
 static gboolean
 populate_buddies_from_nodes (GabbleConnection *conn,
@@ -3086,8 +2976,7 @@ populate_buddies_from_nodes (GabbleConnection *conn,
   return TRUE;
 }
 
-#if 0
-static gboolean
+gboolean
 add_activities_to_view_from_node (GabbleConnection *conn,
                                   GabbleOlpcView *view,
                                   LmMessageNode *node)
@@ -3244,7 +3133,8 @@ activity_added (GabbleConnection *conn,
     return;
 
   id = strtoul (id_str, NULL, 10);
-  view = g_hash_table_lookup (conn->olpc_views, GUINT_TO_POINTER (id));
+  view = gabble_olpc_gadget_manager_get_view (
+      conn->olpc_gadget_manager, id);
   if (view == NULL)
     {
       DEBUG ("no view with ID %u", id);
@@ -3253,7 +3143,6 @@ activity_added (GabbleConnection *conn,
 
   add_activities_to_view_from_node (conn, view, added);
 }
-#endif
 
 /* if activity is not zero, buddies are associated with the given
  * activity room */
@@ -3402,7 +3291,6 @@ buddy_removed (GabbleConnection *conn,
   remove_buddies_from_view_from_node (conn, view, removed);
 }
 
-#if 0
 static gboolean
 remove_activities_from_view_from_node (GabbleConnection *conn,
                                        GabbleOlpcView *view,
@@ -3456,7 +3344,8 @@ activity_removed (GabbleConnection *conn,
     return;
 
   id = strtoul (id_str, NULL, 10);
-  view = g_hash_table_lookup (conn->olpc_views, GUINT_TO_POINTER (id));
+  view = gabble_olpc_gadget_manager_get_view (
+      conn->olpc_gadget_manager, id);
   if (view == NULL)
     {
       DEBUG ("no view with ID %u", id);
@@ -3520,7 +3409,8 @@ activity_membership_change (GabbleConnection *conn,
     return;
 
   id = strtoul (id_str, NULL, 10);
-  view = g_hash_table_lookup (conn->olpc_views, GUINT_TO_POINTER (id));
+  view = gabble_olpc_gadget_manager_get_view (
+      conn->olpc_gadget_manager, id);
   if (view == NULL)
     {
       DEBUG ("no view with ID %u", id);
@@ -3550,7 +3440,6 @@ activity_membership_change (GabbleConnection *conn,
 
   tp_handle_unref (room_repo, handle);
 }
-#endif
 
 LmHandlerResult
 conn_olpc_msg_cb (LmMessageHandler *handler,
@@ -3584,13 +3473,11 @@ conn_olpc_msg_cb (LmMessageHandler *handler,
         {
           buddy_changed (conn, node);
         }
-#if 0
       else if (!tp_strdiff (node->name, "change") &&
           !tp_strdiff (ns, NS_OLPC_ACTIVITY))
         {
           activity_changed (conn, node);
         }
-#endif
       else if (!tp_strdiff (node->name, "added") &&
           !tp_strdiff (ns, NS_OLPC_BUDDY))
         {
@@ -3601,7 +3488,6 @@ conn_olpc_msg_cb (LmMessageHandler *handler,
         {
           buddy_removed (conn, node);
         }
-#if 0
       else if (!tp_strdiff (node->name, "added") &&
           !tp_strdiff (ns, NS_OLPC_ACTIVITY))
         {
@@ -3617,7 +3503,6 @@ conn_olpc_msg_cb (LmMessageHandler *handler,
         {
           activity_membership_change (conn, node);
         }
-#endif
     }
 
   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
@@ -3673,6 +3558,46 @@ disco_item_found_cb (GabbleDisco *disco,
     }
 }
 
+static void
+buddy_activities_changed_cb (GabbleOlpcView *view,
+                             TpHandle contact,
+                             GabbleConnection *conn)
+{
+  GPtrArray *activities;
+
+  /* FIXME: this is not optimal as we completely ignore PEP-announced
+   * activities. Ideally we should cache PEP activities. */
+  activities = gabble_olpc_gadget_manager_find_buddy_activities (
+      conn->olpc_gadget_manager, contact);
+
+  gabble_svc_olpc_buddy_info_emit_activities_changed (conn, contact,
+      activities);
+
+  free_activities (activities);
+}
+
+static void
+gadget_manager_new_channels_cb (GabbleOlpcGadgetManager *mgr,
+                                GHashTable *channels,
+                                GabbleConnection *conn)
+{
+  /* new views has been created */
+  GHashTableIter iter;
+  gpointer key, value;
+
+  g_hash_table_iter_init (&iter, channels);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      if (GABBLE_IS_OLPC_VIEW (key))
+        {
+          GabbleOlpcView *view = GABBLE_OLPC_VIEW (key);
+
+          g_signal_connect (view, "buddy-activities-changed",
+              G_CALLBACK (buddy_activities_changed_cb), conn);
+        }
+    }
+}
+
 void
 conn_olpc_activity_properties_init (GabbleConnection *conn)
 {
@@ -3723,6 +3648,9 @@ conn_olpc_activity_properties_init (GabbleConnection *conn)
 
   g_signal_connect (conn->presence_cache, "presences-updated",
       G_CALLBACK (connection_presences_updated_cb), conn);
+
+  g_signal_connect (conn->olpc_gadget_manager, "new-channels",
+      G_CALLBACK (gadget_manager_new_channels_cb), conn);
 }
 
 static void
@@ -3766,293 +3694,6 @@ olpc_activity_properties_iface_init (gpointer g_iface,
 #undef IMPLEMENT
 }
 
-#if 0
-
-/* FIXME: connect this
-  g_signal_connect (view, "buddy-activities-changed",
-      G_CALLBACK (buddy_activities_changed_cb), conn);
-*/
-
-static void
-buddy_activities_changed_cb (GabbleOlpcView *view,
-                             TpHandle contact,
-                             GabbleConnection *conn)
-{
-  GPtrArray *activities;
-
-  /* FIXME: this is not optimal as we completely ignore PEP-announced
-   * activities. Ideally we should cache PEP activities. */
-  activities = find_buddy_activities_from_views (conn, contact);
-
-  gabble_svc_olpc_buddy_info_emit_activities_changed (conn, contact,
-      activities);
-
-  free_activities (activities);
-}
-
-static LmHandlerResult
-activity_view_query_result_cb (GabbleConnection *conn,
-                               LmMessage *sent_msg,
-                               LmMessage *reply_msg,
-                               GObject *_view,
-                               gpointer user_data)
-{
-  LmMessageNode *view_node;
-  GabbleOlpcView *view = GABBLE_OLPC_VIEW (_view);
-
-  view_node = lm_message_node_get_child_with_namespace (reply_msg->node,
-      "view", NS_OLPC_ACTIVITY);
-  if (view_node == NULL)
-    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
-
-  add_activities_to_view_from_node (conn, view, view_node);
-
-  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
-}
-
-static void
-olpc_gadget_request_random_activities (GabbleSvcOLPCGadget *iface,
-                                       guint max,
-                                       DBusGMethodInvocation *context)
-{
-  GabbleConnection *conn = GABBLE_CONNECTION (iface);
-  LmMessage *query;
-  gchar *max_str, *id_str;
-  gchar *object_path;
-  guint id;
-  GabbleOlpcView *view;
-
-  if (!check_gadget_activity (conn, context))
-    return;
-
-  if (max == 0)
-    {
-      GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-        "max have to be greater than 0" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      return;
-    }
-
-  view = create_view (conn, GABBLE_OLPC_VIEW_TYPE_ACTIVITY);
-  if (view == NULL)
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "can't create view" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      return;
-    }
-
-  g_object_get (view,
-      "id", &id,
-      "object-path", &object_path,
-      NULL);
-
-  max_str = g_strdup_printf ("%u", max);
-  id_str = g_strdup_printf ("%u", id);
-
-  query = lm_message_build_with_sub_type (conn->olpc_gadget_activity,
-      LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
-      '(', "view", "",
-          '@', "xmlns", NS_OLPC_ACTIVITY,
-          '@', "id", id_str,
-          '(', "random", "",
-            '@', "max", max_str,
-          ')',
-      ')',
-      NULL);
-
-  g_free (max_str);
-  g_free (id_str);
-
-  if (!_gabble_connection_send_with_reply (conn, query,
-        activity_view_query_result_cb, G_OBJECT (view), NULL, NULL))
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "Failed to send activity search query to server" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      lm_message_unref (query);
-      g_free (object_path);
-      return;
-    }
-
-  gabble_svc_olpc_gadget_return_from_request_random_activities (context,
-      object_path);
-
-  g_free (object_path);
-  lm_message_unref (query);
-}
-
-static void
-olpc_gadget_search_activities_by_properties (GabbleSvcOLPCGadget *iface,
-                                             GHashTable *properties,
-                                             DBusGMethodInvocation *context)
-{
-  GabbleConnection *conn = GABBLE_CONNECTION (iface);
-  LmMessage *query;
-  LmMessageNode *properties_node;
-  gchar *id_str;
-  gchar *object_path;
-  guint id;
-  GabbleOlpcView *view;
-
-  if (!check_gadget_activity (conn, context))
-    return;
-
-  view = create_view (conn, GABBLE_OLPC_VIEW_TYPE_ACTIVITY);
-  if (view == NULL)
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "can't create view" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      return;
-    }
-
-  g_object_get (view,
-      "id", &id,
-      "object-path", &object_path,
-      NULL);
-
-  id_str = g_strdup_printf ("%u", id);
-
-  query = lm_message_build_with_sub_type (conn->olpc_gadget_activity,
-      LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
-      '(', "view", "",
-          '@', "xmlns", NS_OLPC_ACTIVITY,
-          '@', "id", id_str,
-          '(', "activity", "",
-            '(', "properties", "",
-              '*', &properties_node,
-              '@', "xmlns", NS_OLPC_ACTIVITY_PROPS,
-            ')',
-          ')',
-      ')',
-      NULL);
-
-  g_free (id_str);
-
-  lm_message_node_add_children_from_properties (properties_node, properties,
-      "property");
-
-  if (!_gabble_connection_send_with_reply (conn, query,
-        activity_view_query_result_cb, G_OBJECT (view), NULL, NULL))
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "Failed to send activity search query to server" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      lm_message_unref (query);
-      g_free (object_path);
-      return;
-    }
-
-  gabble_svc_olpc_gadget_return_from_search_activities_by_properties (context,
-      object_path);
-
-  g_free (object_path);
-  lm_message_unref (query);
-}
-
-static void
-olpc_gadget_search_activities_by_participants (GabbleSvcOLPCGadget *iface,
-                                               const GArray *participants,
-                                               DBusGMethodInvocation *context)
-{
-  GabbleConnection *conn = GABBLE_CONNECTION (iface);
-  LmMessage *query;
-  LmMessageNode *activity_node;
-  gchar *id_str;
-  gchar *object_path;
-  guint id, i;
-  GabbleOlpcView *view;
-  TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
-      (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT);
-
-  if (participants->len == 0)
-    {
-     GError error = { TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-        "you must pass at least one participant" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      return;
-    }
-
-  if (!check_gadget_activity (conn, context))
-    return;
-
-  view = create_view (conn, GABBLE_OLPC_VIEW_TYPE_ACTIVITY);
-  if (view == NULL)
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "can't create view" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      return;
-    }
-
-  g_object_get (view,
-      "id", &id,
-      "object-path", &object_path,
-      NULL);
-
-  id_str = g_strdup_printf ("%u", id);
-
-  query = lm_message_build_with_sub_type (conn->olpc_gadget_activity,
-      LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
-      '(', "view", "",
-          '@', "xmlns", NS_OLPC_ACTIVITY,
-          '@', "id", id_str,
-          '(', "activity", "",
-            '*', &activity_node,
-          ')',
-      ')',
-      NULL);
-
-  g_free (id_str);
-
-  for (i = 0; i < participants->len; i++)
-    {
-      LmMessageNode *buddy;
-      const gchar *jid;
-
-      jid = tp_handle_inspect (contact_repo,
-          g_array_index (participants, TpHandle, i));
-
-      buddy = lm_message_node_add_child (activity_node, "buddy", "");
-      lm_message_node_set_attribute (buddy, "jid", jid);
-    }
-
-  if (!_gabble_connection_send_with_reply (conn, query,
-        activity_view_query_result_cb, G_OBJECT (view), NULL, NULL))
-    {
-      GError error = { TP_ERRORS, TP_ERROR_NETWORK_ERROR,
-        "Failed to send activity search query to server" };
-
-      DEBUG ("%s", error.message);
-      dbus_g_method_return_error (context, &error);
-      lm_message_unref (query);
-      g_free (object_path);
-      return;
-    }
-
-  gabble_svc_olpc_gadget_return_from_search_activities_by_participants (
-      context, object_path);
-
-  g_free (object_path);
-  lm_message_unref (query);
-}
-#endif
-
 static gboolean
 send_presence_to_gadget (GabbleConnection *conn,
                          LmMessageSubType sub_type,
diff --git a/src/conn-olpc.h b/src/conn-olpc.h
index 24f53c4..7fe585b 100644
--- a/src/conn-olpc.h
+++ b/src/conn-olpc.h
@@ -72,6 +72,9 @@ gboolean add_buddies_to_view_from_node (GabbleConnection *conn,
     GabbleOlpcView *view, LmMessageNode *node, const gchar *node_name,
     TpHandle activity);
 
+gboolean add_activities_to_view_from_node (GabbleConnection *conn,
+    GabbleOlpcView *view, LmMessageNode *node);
+
 void olpc_gadget_iface_init (gpointer g_iface, gpointer iface_data);
 
 #endif /* __CONN_OLPC_H__ */
diff --git a/src/olpc-activity-view.c b/src/olpc-activity-view.c
new file mode 100644
index 0000000..43659ac
--- /dev/null
+++ b/src/olpc-activity-view.c
@@ -0,0 +1,473 @@
+/*
+ * olpc-activity-view.c - Source for GabbleOlpcActivityView
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "olpc-activity-view.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <loudmouth/loudmouth.h>
+#include <telepathy-glib/channel-iface.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/svc-channel.h>
+#include <telepathy-glib/svc-generic.h>
+
+#define DEBUG_FLAG GABBLE_DEBUG_OLPC
+
+#include "conn-olpc.h"
+#include "debug.h"
+#include "extensions/extensions.h"
+#include "olpc-activity.h"
+#include "namespaces.h"
+#include "util.h"
+
+/* properties */
+enum
+{
+  /* org.laptop.Telepathy.Channel.Type.ActivityView D-Bus properties */
+  PROP_VIEW_PROPERTIES = 1,
+  PROP_PARTICIPANTS,
+
+  PROP_CHANNEL_TYPE,
+  PROP_CHANNEL_PROPERTIES,
+
+  LAST_PROPERTY
+};
+
+typedef struct _GabbleOlpcActivityViewPrivate GabbleOlpcActivityViewPrivate;
+struct _GabbleOlpcActivityViewPrivate
+{
+  GHashTable *properties;
+  TpHandleSet *participants;
+
+  gboolean dispose_has_run;
+};
+
+G_DEFINE_TYPE_WITH_CODE (
+    GabbleOlpcActivityView, gabble_olpc_activity_view, GABBLE_TYPE_OLPC_VIEW,
+    G_IMPLEMENT_INTERFACE (GABBLE_TYPE_SVC_OLPC_CHANNEL_TYPE_ACTIVITYVIEW,
+      NULL);
+    );
+
+#define GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE(obj) \
+    ((GabbleOlpcActivityViewPrivate *) obj->priv)
+
+
+static void
+gabble_olpc_activity_view_init (GabbleOlpcActivityView *self)
+{
+  GabbleOlpcActivityViewPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+      GABBLE_TYPE_OLPC_ACTIVITY_VIEW, GabbleOlpcActivityViewPrivate);
+
+  self->priv = priv;
+
+  priv->dispose_has_run = FALSE;
+}
+
+static void
+gabble_olpc_activity_view_dispose (GObject *object)
+{
+  GabbleOlpcActivityView *self = GABBLE_OLPC_ACTIVITY_VIEW (object);
+  GabbleOlpcActivityViewPrivate *priv = GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  priv->dispose_has_run = TRUE;
+
+  if (G_OBJECT_CLASS (gabble_olpc_activity_view_parent_class)->dispose)
+    G_OBJECT_CLASS (gabble_olpc_activity_view_parent_class)->dispose (object);
+}
+
+static void
+gabble_olpc_activity_view_finalize (GObject *object)
+{
+  GabbleOlpcActivityView *self = GABBLE_OLPC_ACTIVITY_VIEW (object);
+  GabbleOlpcActivityViewPrivate *priv = GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (self);
+
+  g_hash_table_destroy (priv->properties);
+  tp_handle_set_destroy (priv->participants);
+
+  if (G_OBJECT_CLASS (gabble_olpc_activity_view_parent_class)->finalize)
+    G_OBJECT_CLASS (gabble_olpc_activity_view_parent_class)->finalize (object);
+}
+
+static void
+gabble_olpc_activity_view_get_property (GObject *object,
+                                        guint property_id,
+                                        GValue *value,
+                                        GParamSpec *pspec)
+{
+  GabbleOlpcActivityView *self = GABBLE_OLPC_ACTIVITY_VIEW (object);
+  GabbleOlpcActivityViewPrivate *priv = GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (self);
+
+  switch (property_id)
+    {
+      case PROP_CHANNEL_TYPE:
+        g_value_set_static_string (value,
+            GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW);
+        break;
+      case PROP_CHANNEL_PROPERTIES:
+        g_value_take_boxed (value,
+            tp_dbus_properties_mixin_make_properties_hash (object,
+                TP_IFACE_CHANNEL, "TargetHandle",
+                TP_IFACE_CHANNEL, "TargetHandleType",
+                TP_IFACE_CHANNEL, "ChannelType",
+                TP_IFACE_CHANNEL, "TargetID",
+                GABBLE_IFACE_CHANNEL_FUTURE, "InitiatorHandle",
+                GABBLE_IFACE_CHANNEL_FUTURE, "InitiatorID",
+                GABBLE_IFACE_CHANNEL_FUTURE, "Requested",
+                GABBLE_IFACE_OLPC_CHANNEL_INTERFACE_VIEW, "MaxSize",
+                GABBLE_IFACE_OLPC_CHANNEL_INTERFACE_VIEW, "Buddies",
+                GABBLE_IFACE_OLPC_CHANNEL_INTERFACE_VIEW, "Activities",
+                GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW, "Properties",
+                GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW, "Participants",
+                NULL));
+        break;
+      case PROP_VIEW_PROPERTIES:
+        g_value_set_boxed (value, priv->properties);
+        break;
+      case PROP_PARTICIPANTS:
+        g_value_take_boxed (value, tp_handle_set_to_array (priv->participants));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static void
+gabble_olpc_activity_view_set_property (GObject *object,
+                                        guint property_id,
+                                        const GValue *value,
+                                        GParamSpec *pspec)
+{
+  GabbleOlpcActivityView *self = GABBLE_OLPC_ACTIVITY_VIEW (object);
+  GabbleOlpcActivityViewPrivate *priv = GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (self);
+
+  switch (property_id)
+    {
+      case PROP_CHANNEL_TYPE:
+        /* these properties are writable in the interface, but not actually
+         * meaningfully changeable on this channel, so we do nothing */
+        break;
+      case PROP_VIEW_PROPERTIES:
+        priv->properties = g_value_dup_boxed (value);
+        break;
+      case PROP_PARTICIPANTS:
+        {
+          GabbleOlpcView *view = GABBLE_OLPC_VIEW (self);
+          GArray *tmp;
+          guint i;
+          TpHandleRepoIface *contact_repo;
+
+          contact_repo = tp_base_connection_get_handles (
+              TP_BASE_CONNECTION (view->conn), TP_HANDLE_TYPE_CONTACT);
+
+          tmp = g_value_get_boxed (value);
+          if (tmp == NULL)
+            break;
+
+          if (priv->participants != NULL)
+            tp_handle_set_destroy (priv->participants);
+
+          priv->participants = tp_handle_set_new (contact_repo);
+
+          for (i = 0; i < tmp->len; i++)
+            {
+              TpHandle handle = g_array_index (tmp, TpHandle, i);
+
+              tp_handle_set_add (priv->participants, handle);
+            }
+        }
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        break;
+    }
+}
+
+static GObject *
+gabble_olpc_activity_view_constructor (GType type,
+                                       guint n_props,
+                                       GObjectConstructParam *props)
+{
+  GObject *obj;
+  GabbleOlpcView *view;
+  GabbleOlpcActivityViewPrivate *priv;
+  DBusGConnection *bus;
+  TpBaseConnection *conn;
+  TpHandleRepoIface *contact_handles;
+
+  obj = G_OBJECT_CLASS (gabble_olpc_activity_view_parent_class)->
+           constructor (type, n_props, props);
+
+  view = GABBLE_OLPC_VIEW (obj);
+
+  priv = GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (GABBLE_OLPC_ACTIVITY_VIEW (obj));
+  conn = (TpBaseConnection *) view->conn;
+
+  bus = tp_get_bus ();
+  dbus_g_connection_register_g_object (bus, view->object_path, obj);
+
+  contact_handles = tp_base_connection_get_handles (conn,
+      TP_HANDLE_TYPE_CONTACT);
+
+  if (priv->properties == NULL)
+    {
+      priv->properties = g_hash_table_new (g_direct_hash, g_direct_equal);
+    }
+
+  if (priv->participants == NULL)
+    {
+      TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+          TP_BASE_CONNECTION (view->conn), TP_HANDLE_TYPE_CONTACT);
+
+      priv->participants = tp_handle_set_new (contact_repo);
+    }
+
+  return obj;
+}
+
+static LmMessage *
+gabble_olpc_activity_view_create_close_msg (GabbleOlpcView *view)
+{
+  gchar *id_str;
+  LmMessage *msg;
+
+  id_str = g_strdup_printf ("%u", view->id);
+
+  msg = lm_message_build (view->conn->olpc_gadget_activity,
+      LM_MESSAGE_TYPE_MESSAGE,
+      '(', "close", "",
+        '@', "xmlns", NS_OLPC_ACTIVITY,
+        '@', "id", id_str,
+      ')', NULL);
+
+  g_free (id_str);
+
+  return msg;
+}
+
+static LmHandlerResult
+activity_view_query_result_cb (GabbleConnection *conn,
+                               LmMessage *sent_msg,
+                               LmMessage *reply_msg,
+                               GObject *_view,
+                               gpointer user_data)
+{
+  LmMessageNode *view_node;
+  GabbleOlpcView *view = GABBLE_OLPC_VIEW (_view);
+
+  view_node = lm_message_node_get_child_with_namespace (reply_msg->node,
+      "view", NS_OLPC_ACTIVITY);
+  if (view_node == NULL)
+    return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+
+  /* FIXME: make sense to call this conn-olpc function ? */
+  add_activities_to_view_from_node (conn, view, view_node);
+
+  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
+static gboolean
+gabble_olpc_activity_view_send_request (GabbleOlpcView *view,
+                                        GError **error)
+{
+  GabbleOlpcActivityView *self = GABBLE_OLPC_ACTIVITY_VIEW (view);
+  GabbleOlpcActivityViewPrivate *priv = \
+      GABBLE_OLPC_ACTIVITY_VIEW_GET_PRIVATE (self);
+  LmMessage *query;
+  gchar *max_str, *id_str;
+
+  max_str = g_strdup_printf ("%u", view->max_size);
+  id_str = g_strdup_printf ("%u", view->id);
+
+  /* TODO: Implement multi criterias properties */
+  /* TODO: Always use the max_size argument */
+  if (g_hash_table_size (priv->properties) != 0)
+    {
+      LmMessageNode *properties_node;
+
+      query = lm_message_build_with_sub_type (view->conn->olpc_gadget_activity,
+          LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
+          '(', "view", "",
+              '@', "xmlns", NS_OLPC_ACTIVITY,
+              '@', "id", id_str,
+              '(', "activity", "",
+                '(', "properties", "",
+                  '*', &properties_node,
+                  '@', "xmlns", NS_OLPC_ACTIVITY_PROPS,
+                ')',
+              ')',
+          ')',
+          NULL);
+
+      lm_message_node_add_children_from_properties (properties_node,
+          priv->properties, "property");
+    }
+  else if (tp_handle_set_size (priv->participants) != 0)
+    {
+      LmMessageNode *activity_node;
+      GArray *participants;
+      TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
+          TP_BASE_CONNECTION (view->conn), TP_HANDLE_TYPE_CONTACT);
+      guint i;
+
+      query = lm_message_build_with_sub_type (view->conn->olpc_gadget_activity,
+          LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
+          '(', "view", "",
+              '@', "xmlns", NS_OLPC_ACTIVITY,
+              '@', "id", id_str,
+              '(', "activity", "",
+                '*', &activity_node,
+              ')',
+          ')',
+          NULL);
+
+      /* For easier iteration */
+      participants = tp_handle_set_to_array (priv->participants);
+
+      for (i = 0; i < participants->len; i++)
+      {
+        LmMessageNode *buddy;
+        const gchar *jid;
+
+        jid = tp_handle_inspect (contact_repo,
+            g_array_index (participants, TpHandle, i));
+
+        buddy = lm_message_node_add_child (activity_node, "buddy", "");
+        lm_message_node_set_attribute (buddy, "jid", jid);
+      }
+    }
+  else
+    {
+      query = lm_message_build_with_sub_type (view->conn->olpc_gadget_activity,
+          LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_GET,
+          '(', "view", "",
+              '@', "xmlns", NS_OLPC_ACTIVITY,
+              '@', "id", id_str,
+              '(', "random", "",
+                '@', "max", max_str,
+              ')',
+          ')',
+          NULL);
+    }
+
+  g_free (max_str);
+  g_free (id_str);
+
+ if (!_gabble_connection_send_with_reply (view->conn, query,
+        activity_view_query_result_cb, G_OBJECT (self), NULL, NULL))
+    {
+      g_set_error (error, TP_ERRORS, TP_ERROR_NETWORK_ERROR,
+        "Failed to send buddy search query to server");
+
+      DEBUG ("Failed to send activity search query to server");
+      lm_message_unref (query);
+      return FALSE;
+    }
+
+  lm_message_unref (query);
+  return TRUE;
+}
+
+static void
+gabble_olpc_activity_view_class_init (
+    GabbleOlpcActivityViewClass *gabble_olpc_activity_view_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (gabble_olpc_activity_view_class);
+  GabbleOlpcViewClass *view_class = GABBLE_OLPC_VIEW_CLASS (
+      gabble_olpc_activity_view_class);
+  GParamSpec *param_spec;
+  static TpDBusPropertiesMixinPropImpl activity_view_props[] = {
+      { "Properties", "view-properties", NULL },
+      { "Participants", "participants", NULL },
+      { NULL }
+  };
+  static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+      { GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW,
+        tp_dbus_properties_mixin_getter_gobject_properties,
+        NULL,
+        activity_view_props,
+      },
+      { NULL }
+  };
+
+  object_class->get_property = gabble_olpc_activity_view_get_property;
+  object_class->set_property = gabble_olpc_activity_view_set_property;
+  object_class->constructor = gabble_olpc_activity_view_constructor;
+
+  g_type_class_add_private (gabble_olpc_activity_view_class,
+      sizeof (GabbleOlpcActivityViewPrivate));
+
+  object_class->dispose = gabble_olpc_activity_view_dispose;
+  object_class->finalize = gabble_olpc_activity_view_finalize;
+
+  view_class->create_close_msg = gabble_olpc_activity_view_create_close_msg;
+  view_class->send_request = gabble_olpc_activity_view_send_request;
+
+  g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
+      "channel-type");
+  g_object_class_override_property (object_class, PROP_CHANNEL_PROPERTIES,
+      "channel-properties");
+
+  param_spec = g_param_spec_boxed ("view-properties", "View's search properties",
+      "The activity properties Gadget should look for",
+      TP_HASH_TYPE_STRING_VARIANT_MAP,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_VIEW_PROPERTIES,
+      param_spec);
+
+  param_spec = g_param_spec_boxed ("participants", "View's search participants",
+      "The activity participants Gadget should look for",
+      GABBLE_ARRAY_TYPE_HANDLE,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+      G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NAME);
+  g_object_class_install_property (object_class, PROP_PARTICIPANTS,
+      param_spec);
+
+  gabble_olpc_activity_view_class->dbus_props_class.interfaces = prop_interfaces;
+  tp_dbus_properties_mixin_class_init (object_class,
+      G_STRUCT_OFFSET (GabbleOlpcActivityViewClass, dbus_props_class));
+}
+
+GabbleOlpcActivityView *
+gabble_olpc_activity_view_new (GabbleConnection *conn,
+                               const gchar *object_path,
+                               guint id,
+                               guint max_size,
+                               GHashTable *properties,
+                               const GArray *participants)
+
+{
+  return g_object_new (GABBLE_TYPE_OLPC_ACTIVITY_VIEW,
+      "object-path", object_path,
+      "connection", conn,
+      "id", id,
+      "max-size", max_size,
+      "view-properties", properties,
+      "participants", participants,
+      NULL);
+}
diff --git a/src/olpc-activity-view.h b/src/olpc-activity-view.h
new file mode 100644
index 0000000..a5d3ccb
--- /dev/null
+++ b/src/olpc-activity-view.h
@@ -0,0 +1,71 @@
+/*
+ * olpc-activity-view.h - Header for GabbleOlpcActivityView
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GABBLE_OLPC_ACTIVITY_VIEW_H__
+#define __GABBLE_OLPC_ACTIVITY_VIEW_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/handle-repo.h>
+
+#include "olpc-view.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GabbleOlpcActivityView GabbleOlpcActivityView;
+typedef struct _GabbleOlpcActivityViewClass GabbleOlpcActivityViewClass;
+
+struct _GabbleOlpcActivityViewClass {
+  GabbleOlpcViewClass parent_class;
+
+  TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+struct _GabbleOlpcActivityView {
+  GabbleOlpcView parent;
+
+  gpointer priv;
+};
+
+GType gabble_olpc_activity_view_get_type (void);
+
+/* TYPE MACROS */
+#define GABBLE_TYPE_OLPC_ACTIVITY_VIEW \
+  (gabble_olpc_activity_view_get_type ())
+#define GABBLE_OLPC_ACTIVITY_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), GABBLE_TYPE_OLPC_ACTIVITY_VIEW, GabbleOlpcActivityView))
+#define GABBLE_OLPC_ACTIVITY_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), GABBLE_TYPE_OLPC_ACTIVITY_VIEW,\
+                           GabbleOlpcActivityViewClass))
+#define GABBLE_IS_OLPC_ACTIVITY_VIEW(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GABBLE_TYPE_OLPC_ACTIVITY_VIEW))
+#define GABBLE_IS_OLPC_ACTIVITY_VIEW_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GABBLE_TYPE_OLPC_ACTIVITY_VIEW))
+#define GABBLE_OLPC_ACTIVITY_VIEW_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_OLPC_ACTIVITY_VIEW,\
+                              GabbleOlpcActivityViewClass))
+
+GabbleOlpcActivityView * gabble_olpc_activity_view_new (GabbleConnection *conn,
+    const gchar *object_path, guint id, guint max_size, GHashTable *properties,
+    const GArray *participants);
+
+G_END_DECLS
+
+#endif /* #ifndef __GABBLE_OLPC_ACTIVITY_VIEW_H__ */
diff --git a/src/olpc-gadget-manager.c b/src/olpc-gadget-manager.c
index a3cfab4..18fbd13 100644
--- a/src/olpc-gadget-manager.c
+++ b/src/olpc-gadget-manager.c
@@ -39,6 +39,8 @@
 #include "connection.h"
 #include "debug.h"
 #include "namespaces.h"
+#include "olpc-activity.h"
+#include "olpc-activity-view.h"
 #include "olpc-buddy-view.h"
 #include "util.h"
 
@@ -235,16 +237,25 @@ static const gchar * const olpc_gadget_channel_buddy_view_allowed_properties[] =
     NULL
 };
 
+static const gchar * const olpc_gadget_channel_activity_view_allowed_properties[] =
+{
+    GABBLE_IFACE_OLPC_CHANNEL_INTERFACE_VIEW ".MaxSize",
+    GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW ".Properties",
+    GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW ".Participants",
+    NULL
+};
 
 static void
 gabble_olpc_gadget_manager_foreach_channel_class (TpChannelManager *manager,
     TpChannelManagerChannelClassFunc func,
     gpointer user_data)
 {
-  GHashTable *table = g_hash_table_new_full (g_str_hash, g_str_equal,
-      NULL, (GDestroyNotify) tp_g_value_slice_free);
+  GHashTable *table;
   GValue *value;
 
+  /* BuddyView */
+  table = g_hash_table_new_full (g_str_hash, g_str_equal,
+      NULL, (GDestroyNotify) tp_g_value_slice_free);
   value = tp_g_value_slice_new (G_TYPE_STRING);
   g_value_set_static_string (value, GABBLE_IFACE_OLPC_CHANNEL_TYPE_BUDDYVIEW);
   g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
@@ -253,6 +264,18 @@ gabble_olpc_gadget_manager_foreach_channel_class (TpChannelManager *manager,
       user_data);
 
   g_hash_table_destroy (table);
+
+  /* ActivityView */
+  table = g_hash_table_new_full (g_str_hash, g_str_equal,
+      NULL, (GDestroyNotify) tp_g_value_slice_free);
+  value = tp_g_value_slice_new (G_TYPE_STRING);
+  g_value_set_static_string (value, GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW);
+  g_hash_table_insert (table, TP_IFACE_CHANNEL ".ChannelType", value);
+
+  func (manager, table, olpc_gadget_channel_activity_view_allowed_properties,
+      user_data);
+
+  g_hash_table_destroy (table);
 }
 
 static gboolean
@@ -346,6 +369,74 @@ create_buddy_view_channel (GabbleOlpcGadgetManager *self,
   return channel;
 }
 
+static GabbleOlpcView *
+create_activity_view_channel (GabbleOlpcGadgetManager *self,
+                              GHashTable *request_properties,
+                              GError **error)
+{
+  TpBaseConnection *conn = (TpBaseConnection *) self->priv->conn;
+  GabbleOlpcView *channel;
+  guint max_size;
+  gboolean valid;
+  gchar *object_path;
+  GHashTable *properties;
+  GArray *participants;
+
+  /* TODO: check if Gadget is available */
+
+  if ((tp_asv_get_uint32 (request_properties,
+       TP_IFACE_CHANNEL ".TargetHandleType", NULL) != 0) ||
+      (tp_asv_get_uint32 (request_properties,
+      TP_IFACE_CHANNEL ".TargetHandle", NULL) != 0))
+    {
+      g_set_error (error, TP_ERRORS, TP_ERROR_NOT_IMPLEMENTED,
+          "Views channels can't have a target handle");
+      return NULL;
+    }
+
+  if (tp_channel_manager_asv_has_unknown_properties (request_properties,
+          olpc_gadget_channel_view_fixed_properties,
+          olpc_gadget_channel_activity_view_allowed_properties,
+          error))
+    return NULL;
+
+  max_size = tp_asv_get_uint32 (request_properties,
+      GABBLE_IFACE_OLPC_CHANNEL_INTERFACE_VIEW ".MaxSize", &valid);
+  if (!valid)
+    {
+      g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+          "MaxSize property is mandatory");
+      return NULL;
+    }
+
+  if (max_size == 0)
+    {
+
+      g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
+          "max have to be greater than 0");
+      return NULL;
+    }
+
+  properties = tp_asv_get_boxed (request_properties,
+      GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW ".Properties",
+      TP_HASH_TYPE_STRING_VARIANT_MAP);
+
+  participants = tp_asv_get_boxed (request_properties,
+      GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW ".Participants",
+      GABBLE_ARRAY_TYPE_HANDLE);
+
+  object_path = g_strdup_printf ("%s/OlpcActivityViewChannel%u",
+      conn->object_path, self->priv->next_view_number++);
+
+  channel = GABBLE_OLPC_VIEW (gabble_olpc_activity_view_new (self->priv->conn,
+        object_path, self->priv->next_view_number, max_size, properties,
+        participants));
+
+  g_free (object_path);
+
+  return channel;
+}
+
 static gboolean
 gabble_olpc_gadget_manager_handle_request (TpChannelManager *manager,
                                            gpointer request_token,
@@ -362,6 +453,12 @@ gabble_olpc_gadget_manager_handle_request (TpChannelManager *manager,
     {
       channel = create_buddy_view_channel (self, request_properties, &error);
     }
+  else if (!tp_strdiff (tp_asv_get_string (request_properties,
+          TP_IFACE_CHANNEL ".ChannelType"),
+        GABBLE_IFACE_OLPC_CHANNEL_TYPE_ACTIVITYVIEW))
+    {
+      channel = create_activity_view_channel (self, request_properties, &error);
+    }
   else
     {
       return FALSE;
@@ -468,3 +565,81 @@ gabble_olpc_gadget_manager_get_view (GabbleOlpcGadgetManager *self,
 {
   return g_hash_table_lookup (self->priv->channels, GUINT_TO_POINTER (id));
 }
+
+struct find_activities_of_buddy_ctx
+{
+  TpHandle buddy;
+  GHashTable *activities;
+};
+
+static void
+find_activities_of_buddy (TpHandle contact,
+                          GabbleOlpcView *view,
+                          struct find_activities_of_buddy_ctx *ctx)
+{
+  GPtrArray *act;
+  guint i;
+
+  act = gabble_olpc_view_get_buddy_activities (view, ctx->buddy);
+
+  for (i = 0; i < act->len; i++)
+    {
+      GabbleOlpcActivity *activity;
+
+      activity = g_ptr_array_index (act, i);
+      g_hash_table_insert (ctx->activities, GUINT_TO_POINTER (activity->room),
+          activity);
+    }
+
+  g_ptr_array_free (act, TRUE);
+}
+
+static void
+copy_activity_to_array (TpHandle room,
+                        GabbleOlpcActivity *activity,
+                        GPtrArray *activities)
+{
+  GValue gvalue = { 0 };
+
+  if (activity->id == NULL)
+  {
+    DEBUG ("... activity #%u has no ID, skipping", room);
+    return;
+  }
+
+  g_value_init (&gvalue, GABBLE_STRUCT_TYPE_ACTIVITY);
+  g_value_take_boxed (&gvalue, dbus_g_type_specialized_construct
+      (GABBLE_STRUCT_TYPE_ACTIVITY));
+  dbus_g_type_struct_set (&gvalue,
+      0, activity->id,
+      1, activity->room,
+      G_MAXUINT);
+  DEBUG ("... activity #%u (ID %s)",
+      activity->room, activity->id);
+  g_ptr_array_add (activities, g_value_get_boxed (&gvalue));
+}
+
+GPtrArray *
+gabble_olpc_gadget_manager_find_buddy_activities (GabbleOlpcGadgetManager *self,
+                                                  TpHandle contact)
+{
+  GPtrArray *result;
+  struct find_activities_of_buddy_ctx ctx;
+
+  result = g_ptr_array_new ();
+
+  /* We use a hash table first so we won't add twice the same activity */
+  ctx.activities = g_hash_table_new (g_direct_hash, g_direct_equal);
+  ctx.buddy = contact;
+
+  g_hash_table_foreach (self->priv->channels, (GHFunc) find_activities_of_buddy,
+      &ctx);
+
+  /* Now compute the result array using the hash table */
+  g_hash_table_foreach (ctx.activities, (GHFunc) copy_activity_to_array,
+      result);
+
+  g_hash_table_destroy (ctx.activities);
+
+  return result;
+}
diff --git a/src/olpc-gadget-manager.h b/src/olpc-gadget-manager.h
index c508c11..4b9df38 100644
--- a/src/olpc-gadget-manager.h
+++ b/src/olpc-gadget-manager.h
@@ -59,12 +59,16 @@ GType gabble_olpc_gadget_manager_get_type (void);
   (G_TYPE_INSTANCE_GET_CLASS ((obj), GABBLE_TYPE_OLPC_GADGET_MANAGER,\
                               GabbleOlpcGadgetManagerClass))
 
+/* TODO: remove the _from_views */
 GHashTable * gabble_olpc_gadget_manager_find_buddy_properties_from_views (
     GabbleOlpcGadgetManager *self, TpHandle buddy);
 
 GabbleOlpcView * gabble_olpc_gadget_manager_get_view (
     GabbleOlpcGadgetManager *self, guint id);
 
+GPtrArray * gabble_olpc_gadget_manager_find_buddy_activities (
+    GabbleOlpcGadgetManager *self, TpHandle contact);
+
 G_END_DECLS
 
 #endif
diff --git a/tests/twisted/olpc/olpc-activity-search.py b/tests/twisted/olpc/olpc-activity-search.py
index ba865cc..51c25be 100644
--- a/tests/twisted/olpc/olpc-activity-search.py
+++ b/tests/twisted/olpc/olpc-activity-search.py
@@ -2,10 +2,6 @@
 test OLPC search activity
 """
 
-print "FIXME: olpc/olpc-activity-search.py disabled during requestotronification of the view API"
-# exiting 77 causes automake to consider the test to have been skipped
-raise SystemExit(77)
-
 import dbus
 
 from servicetest import call_async, EventPattern
@@ -31,11 +27,19 @@ NS_DISCO_ITEMS = "http://jabber.org/protocol/disco#items"
 NS_AMP = "http://jabber.org/protocol/amp"
 NS_STANZA = "urn:ietf:params:xml:ns:xmpp-stanzas"
 
+tp_name_prefix = 'org.freedesktop.Telepathy'
+olpc_name_prefix = 'org.laptop.Telepathy'
+
 def check_view(view, conn, activities, buddies):
-    act = view.GetActivities()
+    act = view.Get(olpc_name_prefix + '.Channel.Interface.View',
+        'Activities',
+        dbus_interface='org.freedesktop.DBus.Properties')
+
     assert sorted(act) == sorted(activities)
 
-    handles = view.GetBuddies()
+    handles = view.Get(olpc_name_prefix + '.Channel.Interface.View',
+        'Buddies',
+        dbus_interface='org.freedesktop.DBus.Properties')
     assert sorted(conn.InspectHandles(1, handles)) == sorted(buddies)
 
 def test(q, bus, conn, stream):
@@ -56,18 +60,60 @@ def test(q, bus, conn, stream):
             'org.laptop.Telepathy.ActivityProperties')
     buddy_prop_iface = dbus.Interface(conn, 'org.laptop.Telepathy.BuddyInfo')
     gadget_iface = dbus.Interface(conn, 'org.laptop.Telepathy.Gadget')
+    requests_iface = dbus.Interface(conn, tp_name_prefix + '.Connection.Interface.Requests')
 
     sync_stream(q, stream)
 
+    # TODO: change view var name
+
+    # check if we can request Activity views
+    properties = conn.GetAll(
+        'org.freedesktop.Telepathy.Connection.Interface.Requests',
+        dbus_interface='org.freedesktop.DBus.Properties')
+
+    assert ({tp_name_prefix + '.Channel.ChannelType':
+            olpc_name_prefix + '.Channel.Type.ActivityView'},
+
+            [olpc_name_prefix + '.Channel.Interface.View.MaxSize',
+             olpc_name_prefix + '.Channel.Type.ActivityView.Properties',
+             olpc_name_prefix + '.Channel.Type.ActivityView.Participants'],
+         ) in properties.get('RequestableChannelClasses'),\
+                 properties['RequestableChannelClasses']
+
     # request 3 random activities (view 0)
-    view_path = request_random_activity_view(q, stream, conn, 3, '0',
+    view_path = request_random_activity_view(q, stream, conn, 3, '1',
             [('activity1', 'room1 at conference.localhost',
                 {'color': ('str', '#005FE4,#00A0FF')},
                 [('lucien at localhost', {'color': ('str', '#AABBCC,#CCBBAA')}),
                  ('jean at localhost', {})]),])
 
     view0 = bus.get_object(conn.bus_name, view_path)
-    view0_iface = dbus.Interface(view0, 'org.laptop.Telepathy.View')
+
+    # check org.freedesktop.Telepathy.Channel D-Bus properties
+    props = view0.GetAll(
+        'org.freedesktop.Telepathy.Channel',
+        dbus_interface='org.freedesktop.DBus.Properties')
+
+    assert props['ChannelType'] == 'org.laptop.Telepathy.Channel.Type.ActivityView'
+    assert 'org.laptop.Telepathy.Channel.Interface.View' in props['Interfaces']
+    assert props['TargetHandle'] == 0
+    assert props['TargetID'] == ''
+    assert props['TargetHandleType'] == 0
+
+    # check org.laptop.Telepathy.Channel.Interface.View D-Bus properties
+    props = view0.GetAll(
+        'org.laptop.Telepathy.Channel.Interface.View',
+        dbus_interface='org.freedesktop.DBus.Properties')
+
+    assert props['MaxSize'] == 3
+
+    # check org.laptop.Telepathy.Channel.Type.ActivityView D-Bus properties
+    props = view0.GetAll(
+        'org.laptop.Telepathy.Channel.Type.ActivityView',
+        dbus_interface='org.freedesktop.DBus.Properties')
+
+    assert props['Properties'] == {}
+    assert props['Participants'] == []
 
     ## Current views ##
     # view 0: activity 1 (with: Lucien, Jean)
@@ -82,7 +128,7 @@ def test(q, bus, conn, stream):
     assert props == {'color': '#005FE4,#00A0FF'}
 
     q.expect('dbus-signal', signal='ActivitiesChanged',
-            interface='org.laptop.Telepathy.View',
+            interface='org.laptop.Telepathy.Channel.Interface.View',
             args=[[('activity1', handles['room1'])], []])
 
     # participants are added to view
@@ -99,7 +145,7 @@ def test(q, bus, conn, stream):
             args=[handles['jean'], [('activity1', handles['room1'])]]))
 
     # check activities and buddies in view
-    check_view(view0_iface, conn, [('activity1', handles['room1'])],
+    check_view(view0, conn, [('activity1', handles['room1'])],
             ['lucien at localhost', 'jean at localhost'])
 
     # we can now get activity properties
@@ -122,13 +168,19 @@ def test(q, bus, conn, stream):
             value=([('activity1', handles['room1'])],))
 
     # activity search by properties (view 1)
-    props = {'color': '#AABBCC,#001122'}
-    call_async(q, gadget_iface, 'SearchActivitiesByProperties', props)
+    props = dbus.Dictionary({'color': '#AABBCC,#001122'}, signature='sv')
+
+    call_async(q, requests_iface, 'CreateChannel',
+        { 'org.freedesktop.Telepathy.Channel.ChannelType':
+            'org.laptop.Telepathy.Channel.Type.ActivityView',
+            'org.laptop.Telepathy.Channel.Interface.View.MaxSize': 5,
+            'org.laptop.Telepathy.Channel.Type.ActivityView.Properties': props,
+          })
 
     iq_event, return_event = q.expect_many(
         EventPattern('stream-iq', to='gadget.localhost',
             query_ns=NS_OLPC_ACTIVITY),
-        EventPattern('dbus-return', method='SearchActivitiesByProperties'))
+        EventPattern('dbus-return', method='CreateChannel'))
 
     properties_nodes = xpath.queryForNodes('/iq/view/activity/properties',
             iq_event.stanza)
@@ -137,7 +189,7 @@ def test(q, bus, conn, stream):
 
     view = iq_event.stanza.firstChildElement()
     assert view.name == 'view'
-    assert view['id'] == '1'
+    assert view['id'] == '2'
 
     send_reply_to_activity_view_request(stream, iq_event.stanza,
             [('activity2', 'room2 at conference.localhost',
@@ -149,7 +201,11 @@ def test(q, bus, conn, stream):
 
     view_path = return_event.value[0]
     view1 = bus.get_object(conn.bus_name, view_path)
-    view1_iface = dbus.Interface(view1, 'org.laptop.Telepathy.View')
+
+    props = return_event.value[1]
+    assert props['org.laptop.Telepathy.Channel.Type.ActivityView.Properties'] == \
+            {'color': '#AABBCC,#001122'}
+    assert props['org.laptop.Telepathy.Channel.Type.ActivityView.Participants'] == []
 
     event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')
     handles['room2'], props = event.args
@@ -157,27 +213,38 @@ def test(q, bus, conn, stream):
     assert props == {'color': '#AABBCC,#001122'}
 
     q.expect('dbus-signal', signal='ActivitiesChanged',
-            interface='org.laptop.Telepathy.View',
+            interface='org.laptop.Telepathy.Channel.Interface.View',
             args=[[('activity2', handles['room2'])], []])
 
-    act = view1.GetActivities()
+    act = view1.Get(olpc_name_prefix + '.Channel.Interface.View',
+        'Activities',
+        dbus_interface='org.freedesktop.DBus.Properties')
     assert sorted(act) == [('activity2', handles['room2'])]
 
-    assert view1_iface.GetBuddies() == []
+    buddies = view1.Get(olpc_name_prefix + '.Channel.Interface.View',
+        'Buddies',
+        dbus_interface='org.freedesktop.DBus.Properties')
+    assert buddies == []
 
     # activity search by participants (view 2)
     participants = conn.RequestHandles(1, ["alice at localhost", "bob at localhost"])
-    call_async(q, gadget_iface, 'SearchActivitiesByParticipants', participants)
+
+    call_async(q, requests_iface, 'CreateChannel',
+        { 'org.freedesktop.Telepathy.Channel.ChannelType':
+            'org.laptop.Telepathy.Channel.Type.ActivityView',
+            'org.laptop.Telepathy.Channel.Interface.View.MaxSize': 5,
+            'org.laptop.Telepathy.Channel.Type.ActivityView.Participants': participants,
+          })
 
     iq_event, return_event = q.expect_many(
         EventPattern('stream-iq', to='gadget.localhost',
             query_ns=NS_OLPC_ACTIVITY),
-        EventPattern('dbus-return', method='SearchActivitiesByParticipants'))
+        EventPattern('dbus-return', method='CreateChannel'))
 
     buddies = xpath.queryForNodes('/iq/view/activity/buddy', iq_event.stanza)
     view = iq_event.stanza.firstChildElement()
     assert view.name == 'view'
-    assert view['id'] == '2'
+    assert view['id'] == '3'
     assert len(buddies) == 2
     assert (buddies[0]['jid'], buddies[1]['jid']) == ('alice at localhost',
             'bob at localhost')
@@ -193,7 +260,6 @@ def test(q, bus, conn, stream):
 
     view_path = return_event.value[0]
     view2 = bus.get_object(conn.bus_name, view_path)
-    view2_iface = dbus.Interface(view2, 'org.laptop.Telepathy.View')
 
     event = q.expect('dbus-signal', signal='ActivityPropertiesChanged')
     handles['room3'], props = event.args
@@ -201,17 +267,19 @@ def test(q, bus, conn, stream):
     assert props == {'color': '#AABBCC,#001122'}
 
     q.expect('dbus-signal', signal='ActivitiesChanged',
-            interface='org.laptop.Telepathy.View',
+            interface='org.laptop.Telepathy.Channel.Interface.View',
             args=[[('activity3', handles['room3'])], []])
 
-    act = view2.GetActivities()
+    act = view2.Get(olpc_name_prefix + '.Channel.Interface.View',
+        'Activities',
+        dbus_interface='org.freedesktop.DBus.Properties')
     assert sorted(act) == [('activity3', handles['room3'])]
 
     # add activity 4 to view 0
     message = create_gadget_message('alice at localhost')
 
     added = message.addElement((NS_OLPC_ACTIVITY, 'added'))
-    added['id'] = '0'
+    added['id'] = '1'
     activity = added.addElement((None, 'activity'))
     activity['id'] = 'activity4'
     activity['room'] = 'room4 at conference.localhost'
@@ -238,7 +306,7 @@ def test(q, bus, conn, stream):
 
     # activity is added
     event = q.expect('dbus-signal', signal='ActivitiesChanged',
-            interface='org.laptop.Telepathy.View')
+            interface='org.laptop.Telepathy.Channel.Interface.View')
     added, removed = event.args
     assert len(added) == 1
     id, handles['room4'] = added[0]
@@ -261,7 +329,7 @@ def test(q, bus, conn, stream):
                 ('activity4', handles['room4'])]]))
 
     # check activities and buddies in view
-    check_view(view0_iface, conn, [
+    check_view(view0, conn, [
         ('activity1', handles['room1']), ('activity4', handles['room4'])],
         ['fernand at localhost', 'lucien at localhost', 'jean at localhost'])
 
@@ -275,7 +343,7 @@ def test(q, bus, conn, stream):
     change = message.addElement((NS_OLPC_ACTIVITY, 'change'))
     change['activity'] = 'activity1'
     change['room'] = 'room1 at conference.localhost'
-    change['id'] = '0'
+    change['id'] = '1'
     properties = change.addElement((NS_OLPC_ACTIVITY_PROPS, 'properties'))
     for node in properties_to_xml({'tags': ('str', 'game'), \
             'color': ('str', '#AABBAA,#BBAABB')}):
@@ -295,7 +363,7 @@ def test(q, bus, conn, stream):
 
     activity = message.addElement((NS_OLPC_ACTIVITY, 'activity'))
     activity['room'] = 'room1 at conference.localhost'
-    activity['view'] = '0'
+    activity['view'] = '1'
     joined = activity.addElement((None, 'joined'))
     joined['jid'] = 'marcel at localhost'
     properties = joined.addElement((NS_OLPC_BUDDY_PROPS, "properties"))
@@ -322,7 +390,7 @@ def test(q, bus, conn, stream):
                 args=[handles['marcel'], [('activity1', handles['room1'])]]))
 
     # check activities and buddies in view
-    check_view(view0_iface, conn, [
+    check_view(view0, conn, [
         ('activity1', handles['room1']),('activity4', handles['room4'])],
         ['fernand at localhost', 'lucien at localhost', 'jean at localhost',
             'marcel at localhost'])
@@ -332,7 +400,7 @@ def test(q, bus, conn, stream):
 
     activity = message.addElement((NS_OLPC_ACTIVITY, 'activity'))
     activity['room'] = 'room1 at conference.localhost'
-    activity['view'] = '0'
+    activity['view'] = '1'
     left = activity.addElement((None, 'left'))
     left['jid'] = 'marcel at localhost'
 
@@ -351,7 +419,7 @@ def test(q, bus, conn, stream):
                 args=[handles['marcel'], []]))
 
     # check activities and buddies in view
-    check_view(view0_iface, conn, [
+    check_view(view0, conn, [
         ('activity1', handles['room1']),('activity4', handles['room4'])],
         ['fernand at localhost', 'lucien at localhost', 'jean at localhost'])
 
@@ -360,7 +428,7 @@ def test(q, bus, conn, stream):
 
     activity = message.addElement((NS_OLPC_ACTIVITY, 'activity'))
     activity['room'] = 'room1 at conference.localhost'
-    activity['view'] = '0'
+    activity['view'] = '1'
     left = activity.addElement((None, 'left'))
     left['jid'] = 'jean at localhost'
 
@@ -376,7 +444,7 @@ def test(q, bus, conn, stream):
             args=[handles['jean'], [('activity4', handles['room4'])]])
 
     # Jean wasn't removed from the view as he is still in activity 4
-    check_view(view0_iface, conn, [
+    check_view(view0, conn, [
         ('activity1', handles['room1']),('activity4', handles['room4'])],
         ['fernand at localhost', 'lucien at localhost', 'jean at localhost'])
 
@@ -384,7 +452,7 @@ def test(q, bus, conn, stream):
     message = create_gadget_message('alice at localhost')
 
     removed = message.addElement((NS_OLPC_ACTIVITY, 'removed'))
-    removed['id'] = '0'
+    removed['id'] = '1'
     activity = removed.addElement((None, 'activity'))
     activity['id'] = 'activity1'
     activity['room'] = 'room1 at conference.localhost'
@@ -402,19 +470,19 @@ def test(q, bus, conn, stream):
                 args=[[], [handles['lucien']]]),
     # activity is removed from the view
             EventPattern('dbus-signal', signal='ActivitiesChanged',
-                interface='org.laptop.Telepathy.View',
+                interface='org.laptop.Telepathy.Channel.Interface.View',
                 args=[[], [('activity1', handles['room1'])]]),
             EventPattern('dbus-signal', signal='ActivitiesChanged',
                 interface='org.laptop.Telepathy.BuddyInfo',
                 args=[handles['lucien'], []]))
 
     # check activities and buddies in view
-    check_view(view0_iface, conn, [
+    check_view(view0, conn, [
         ('activity4', handles['room4'])],
         ['fernand at localhost', 'jean at localhost'])
 
     # close view 0
-    call_async(q, view0_iface, 'Close')
+    call_async(q, view0, 'Close')
     event_msg, _, _, _ = q.expect_many(
         EventPattern('stream-message', to='gadget.localhost'),
         EventPattern('dbus-return', method='Close'),
@@ -428,13 +496,13 @@ def test(q, bus, conn, stream):
 
     close = xpath.queryForNodes('/message/close', event_msg.stanza)
     assert len(close) == 1
-    assert close[0]['id'] == '0'
+    assert close[0]['id'] == '1'
 
     # close view 1
-    close_view(q, view1_iface, '1')
+    close_view(q, view1, '2')
 
     # close view 2
-    close_view(q, view2_iface, '2')
+    close_view(q, view2, '3')
 
 if __name__ == '__main__':
     exec_test(test)
diff --git a/tests/twisted/olpc/util.py b/tests/twisted/olpc/util.py
index 949433a..eafdb84 100644
--- a/tests/twisted/olpc/util.py
+++ b/tests/twisted/olpc/util.py
@@ -183,14 +183,18 @@ def send_reply_to_activity_view_request(stream, stanza, activities):
     stream.send(reply)
 
 def request_random_activity_view(q, stream, conn, max, id, activities):
-    gadget_iface = dbus.Interface(conn, 'org.laptop.Telepathy.Gadget')
+    requests_iface = dbus.Interface(conn, 'org.freedesktop.Telepathy.Connection.Interface.Requests')
 
-    call_async(q, gadget_iface, 'RequestRandomActivities', max)
+    call_async(q, requests_iface, 'CreateChannel',
+        { 'org.freedesktop.Telepathy.Channel.ChannelType':
+            'org.laptop.Telepathy.Channel.Type.ActivityView',
+            'org.laptop.Telepathy.Channel.Interface.View.MaxSize': max
+          })
 
     iq_event, return_event = q.expect_many(
     EventPattern('stream-iq', to='gadget.localhost',
         query_ns=NS_OLPC_ACTIVITY),
-    EventPattern('dbus-return', method='RequestRandomActivities'))
+    EventPattern('dbus-return', method='CreateChannel'))
 
     view = iq_event.stanza.firstChildElement()
     assert view.name == 'view'
@@ -201,6 +205,10 @@ def request_random_activity_view(q, stream, conn, max, id, activities):
 
     send_reply_to_activity_view_request(stream, iq_event.stanza, activities)
 
+    props = return_event.value[1]
+    assert props['org.laptop.Telepathy.Channel.Type.ActivityView.Properties'] == {}
+    assert props['org.laptop.Telepathy.Channel.Type.ActivityView.Participants'] == []
+
     return return_event.value[0]
 
 def close_view(q, view, id):
-- 
1.5.6.5




More information about the Telepathy-commits mailing list