Screen-reader refactor;
authorMateusz Żakowski <m.zakowski@samsung.com>
Tue, 10 Feb 2015 16:26:14 +0000 (17:26 +0100)
committerMateusz Żakowski <m.zakowski@samsung.com>
Tue, 24 Feb 2015 11:02:00 +0000 (12:02 +0100)
-smart-notifications added;
-system-notifications added;
-code refactored;
-queue flush flag implemented;
-screen-reader pause api added;
-scroll start/end handler added;

Change-Id: I5326b4bad812e8ef3f7fc8d2443dcb05831def12

18 files changed:
CMakeLists.txt
include/logger.h
include/navigator.h
include/screen_reader.h
include/screen_reader_haptic.h [new file with mode: 0644]
include/screen_reader_system.h [new file with mode: 0644]
include/screen_reader_tts.h
include/smart_notification.h [new file with mode: 0644]
org.tizen.smart-navigator.manifest
packaging/org.tizen.smart-navigator.spec
src/navigator.c
src/screen_reader.c
src/screen_reader_haptic.c [new file with mode: 0644]
src/screen_reader_spi.c
src/screen_reader_system.c [new file with mode: 0644]
src/screen_reader_tts.c
src/screen_reader_xml.c
src/smart_notification.c [new file with mode: 0644]

index 10e6629..1e61afb 100755 (executable)
@@ -20,7 +20,8 @@ pkg_check_modules(pkgs REQUIRED
        dlog
        vconf
        tts
-
+       capi-media-tone-player
+       capi-system-device
 )
 
 FOREACH(flag ${pkgs_CFLAGS})
index c0a2eb7..b0fdbc0 100644 (file)
@@ -13,4 +13,6 @@ void logger_shutdown(void);
 #define ERROR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__);
 #define WARNING(...) EINA_LOG_DOM_WRN(_eina_log_dom, __VA_ARGS__);
 
+#define MEMORY_ERROR "Memory allocation error"
+
 #endif /* end of include guard: LOGGER_H_ */
index a797801..a61932a 100644 (file)
@@ -1,2 +1,4 @@
+#include <atspi/atspi.h>
+
 void navigator_init(void);
 void navigator_shutdown(void);
index dc7735e..177c20f 100644 (file)
@@ -48,8 +48,6 @@ typedef struct _Service_Data
        tts_h tts;
        Eina_List *available_languages;
 
-       char *text_to_say_text;
-       char *description_text;
        char *text_to_say_info;
        char *current_value;
        char *current_char;
diff --git a/include/screen_reader_haptic.h b/include/screen_reader_haptic.h
new file mode 100644 (file)
index 0000000..d3f9beb
--- /dev/null
@@ -0,0 +1,4 @@
+void haptic_module_init(void);
+void haptic_module_disconnect(void);
+void haptic_vibrate_start(void);
+void haptic_vibrate_stop(void);
diff --git a/include/screen_reader_system.h b/include/screen_reader_system.h
new file mode 100644 (file)
index 0000000..bafe015
--- /dev/null
@@ -0,0 +1,2 @@
+void system_notifications_init(void);
+void system_notifications_shutdown(void);
\ No newline at end of file
index 8ab3092..46da847 100644 (file)
@@ -18,9 +18,7 @@ extern int speed;
 
 bool tts_init(void *data);
 void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data);
-bool update_supported_voices(void *data);
-void spi_prepare_text(void *data);
-void tts_append_text(void *data);
+Eina_Bool tts_speak(char *text_to_speak, Eina_Bool flush_switch);
 void spi_stop(void *data);
 
 #endif /* SCREEN_READER_TTS_H_ */
diff --git a/include/smart_notification.h b/include/smart_notification.h
new file mode 100644 (file)
index 0000000..1f62150
--- /dev/null
@@ -0,0 +1,14 @@
+#include "screen_reader.h"
+#include "screen_reader_haptic.h"
+#include "logger.h"
+
+enum _Notification_Type {
+     FOCUS_CHAIN_END_NOTIFICATION_EVENT,
+     REALIZED_ITEMS_NOTIFICATION_EVENT,
+};
+
+typedef enum _Notification_Type Notification_Type;
+
+void smart_notification_init(void);
+void smart_notification(Notification_Type nt, int start_index, int end_index);
+void smart_notification_shutdown(void);
index 36d012a..3bc75b5 100644 (file)
@@ -6,6 +6,10 @@
        <smack permit="atspi" type="rwx" />
        <smack permit="e17" type="rwx" />
        <smack permit="tts-server" type="rwx" />
+       <smack permit="media-controller-client" type="rwx" />
+       <smack permit="deviced" type="rwx" />
+       <smack permit="sensord" type="rwx" />
+       <smack permit="media-server" type="rwx" />
     </permit>
     <request>
        <smack request="sdbd" type="rwx" />
        <smack request="svi-data" type="rwx" />
        <smack request="e17" type="rwx" />
        <smack request="tts-server" type="rwx" />
+       <smack request="media-controller-client" type="rwx" />
+       <smack request="sound_server" type="rwx" />
+       <smack request="deviced" type="rwx" />
+       <smack request="sensord" type="rwx" />
+       <smack request="media-server" type="rwx" />
     </request>
  </define>
 
index 1c3de94..97073c4 100755 (executable)
@@ -18,6 +18,8 @@ BuildRequires:  pkgconfig(ecore-x)
 BuildRequires:  pkgconfig(eina)
 BuildRequires:  pkgconfig(eldbus)
 BuildRequires:  pkgconfig(elementary)
+BuildRequires:  pkgconfig(capi-media-tone-player)
+BuildRequires:  pkgconfig(capi-system-device)
 BuildRequires:  tts
 BuildRequires:  tts-devel
 BuildRequires:  vconf
index b6556dc..0580620 100644 (file)
@@ -11,6 +11,8 @@
 #include "object_cache.h"
 #include "flat_navi.h"
 #include "app_tracker.h"
+#include "smart_notification.h"
+#include "screen_reader_system.h"
 
 #define QUICKPANEL_DOWN TRUE
 #define QUICKPANEL_UP FALSE
@@ -84,6 +86,7 @@ _current_highlight_object_set(AtspiAccessible *obj)
                role,
                name,
                oc->bounds->x, oc->bounds->y, oc->bounds->width, oc->bounds->height);
+             haptic_vibrate_start();
          }
          else {
            name = atspi_accessible_get_name(obj, &err);
@@ -94,6 +97,7 @@ _current_highlight_object_set(AtspiAccessible *obj)
                name,
                role
                );
+           haptic_vibrate_start();
                }
          g_free(role);
          g_free(name);
@@ -305,12 +309,13 @@ static void _focus_next(void)
    obj = flat_navi_context_next(context);
    // try next line
    if (!obj)
-     obj = flat_navi_context_line_next(context);
+        obj = flat_navi_context_line_next(context);
    // try 'cycle' objects in context
    if (!obj)
      {
         flat_navi_context_line_first(context);
         obj = flat_navi_context_first(context);
+        smart_notification(FOCUS_CHAIN_END_NOTIFICATION_EVENT, 0, 0);
      }
    if (obj)
      _current_highlight_object_set(obj);
@@ -339,6 +344,7 @@ static void _focus_prev(void)
      {
         flat_navi_context_line_last(context);
         obj = flat_navi_context_last(context);
+        smart_notification(FOCUS_CHAIN_END_NOTIFICATION_EVENT, 0, 0);
      }
    if (obj)
      _current_highlight_object_set(obj);
@@ -844,6 +850,8 @@ void navigator_init(void)
    window_tracker_register(on_window_activate, NULL);
    window_tracker_active_window_request();
    app_tracker_init();
+   smart_notification_init();
+   system_notifications_init();
 }
 
 void navigator_shutdown(void)
@@ -866,4 +874,6 @@ void navigator_shutdown(void)
    object_cache_shutdown();
    app_tracker_shutdown();
    window_tracker_shutdown();
+   smart_notification_shutdown();
+   system_notifications_shutdown();
 }
index 4108d71..5c82d63 100755 (executable)
@@ -1,5 +1,8 @@
 #include "screen_reader.h"
 #include "screen_reader_tts.h"
+#include "screen_reader_vconf.h"
+#include "screen_reader_spi.h"
+#include "screen_reader_xml.h"
 #include <vconf.h>
 #include "logger.h"
 
@@ -25,11 +28,8 @@ Service_Data service_data = {
                .available_languages = NULL,
 
                //Actions to do when tts state is 'ready'
-               .say_text = false,
                .update_language_list = false,
 
-
-               .text_to_say_text = NULL,
                .text_to_say_info = NULL
 };
 
@@ -90,8 +90,6 @@ int screen_reader_terminate_service(void *data)
        tts_stop(service_data->tts);
        tts_unprepare(service_data->tts);
        tts_destroy(service_data->tts);
-       service_data->text_to_say_text = NULL;
-       service_data->description_text = NULL;
        service_data->text_from_dbus = NULL;
        service_data->current_value = NULL;
 
diff --git a/src/screen_reader_haptic.c b/src/screen_reader_haptic.c
new file mode 100644 (file)
index 0000000..a0f5a1a
--- /dev/null
@@ -0,0 +1,99 @@
+#include <device/haptic.h>
+#include "smart_notification.h"
+
+static haptic_device_h handle;
+static haptic_effect_h effect_handle;
+
+#define RED  "\x1B[31m"
+#define RESET "\033[0m"
+
+/**
+ * @brief Initializer for haptic module
+ *
+ */
+void haptic_module_init(void)
+{
+    int num;
+
+    if(!device_haptic_get_count(&num))
+      {
+         DEBUG(RED"Haptic device received!"RESET);
+      }
+    else
+      {
+         ERROR("Cannot receive haptic device count");
+         return;
+      }
+
+    if(!device_haptic_open(0, &handle))
+      {
+         DEBUG(RED"Device connected!"RESET);
+      }
+    else
+      {
+         ERROR("Cannot open haptic device");
+      }
+}
+
+/**
+ * @brief Disconnect haptic handle
+ *
+ */
+void haptic_module_disconnect(void)
+{
+    if(!handle)
+      {
+         ERROR("Haptic handle lost");
+         return;
+      }
+    if(!device_haptic_close(handle))
+      {
+         DEBUG("Haptic disconnected");
+      }
+    else
+      {
+         ERROR("Haptic close error");
+      }
+}
+
+/**
+ * @brief Start vibrations
+ *
+ */
+void haptic_vibrate_start(void)
+{
+    if(!handle)
+      {
+         ERROR("Haptic handle lost");
+         return;
+      }
+    if(!device_haptic_vibrate(handle, 1000, 100, &effect_handle))
+      {
+         DEBUG(RED"Vibrations started!"RESET);
+      }
+    else
+      {
+         ERROR("Cannot start vibration");
+      }
+}
+
+/**
+ * @brief Stop vibrations
+ *
+ */
+void haptic_vibrate_stop(void)
+{
+    if(!handle)
+      {
+         ERROR("Haptic handle lost");
+         return;
+      }
+    if(!device_haptic_stop(handle, &effect_handle))
+      {
+         ERROR("Vibrations stopped!");
+      }
+    else
+      {
+         DEBUG(RED"Cannot stop vibration"RESET);
+      }
+}
index 5cb5baf..cea15c5 100644 (file)
  *  Author: m.skorupinsk
  */
 
+#define _GNU_SOURCE
+
+#include <stdio.h>
 #include "screen_reader_spi.h"
 #include "screen_reader_xml.h"
+#include "screen_reader_tts.h"
 #include "logger.h"
 #ifdef RUN_IPC_TEST_SUIT
-       #include "test_suite/test_suite.h"
+    #include "test_suite/test_suite.h"
 #endif
 
+#define NO_VALUE_INTERFACE "No value interface present"
+#define NO_TEXT_INTERFACE "No text interface present"
+
+/** @brief Service_Data used as screen reader internal data struct*/
 static Service_Data *service_data;
 
 typedef struct
 {
-       char *key;
-       char *val;
+    char *key;
+    char *val;
 } Attr;
 
+
+/**
+ * @brief Debug function. Print current toolkit version/event
+ * type/event source/event detail1/event detail2
+ *
+ * @param AtspiEvent instance
+ *
+ */
 static void display_info(const AtspiEvent *event)
 {
-       AtspiAccessible  *source = event->source;
-       gchar *name= atspi_accessible_get_name(source, NULL);
-       gchar *role= atspi_accessible_get_role_name(source, NULL);
-       gchar *toolkit = atspi_accessible_get_toolkit_name(source, NULL);
-
-       DEBUG("--------------------------------------------------------");
-       DEBUG("Toolkit: %s; Event_type: %s; (%d, %d)", toolkit, event->type, event->detail1, event->detail2);
-       DEBUG("Name: %s; Role: %s", name, role);
-       DEBUG("--------------------------------------------------------");
+    AtspiAccessible  *source = event->source;
+    gchar *name= atspi_accessible_get_name(source, NULL);
+    gchar *role= atspi_accessible_get_role_name(source, NULL);
+    gchar *toolkit = atspi_accessible_get_toolkit_name(source, NULL);
+
+    DEBUG("--------------------------------------------------------");
+    DEBUG("Toolkit: %s; Event_type: %s; (%d, %d)", toolkit, event->type, event->detail1, event->detail2);
+    DEBUG("Name: %s; Role: %s", name, role);
+    DEBUG("--------------------------------------------------------");
 }
 
 Eina_Bool double_click_timer_cb(void *data)
 {
-       Service_Data *sd = data;
-       sd->clicked_widget = NULL;
+    Service_Data *sd = data;
+    sd->clicked_widget = NULL;
 
-       return EINA_FALSE;
+    return EINA_FALSE;
 }
 
+/**
+  * @brief Atspi tracking-signal callback passing current highlighted/focused
+  * accessible description to TTS
+  *
+  * @param AtspiEvent instance
+  * @param user_data screen-reader internal data
+  *
+**/
 void spi_on_state_changed_cb(const AtspiEvent *event, void *user_data)
 {
-       DEBUG("START");
-       DEBUG("STATE CHANGED");
-       Service_Data *sd = user_data;
-
-       display_info(event);
-       if(strcmp(event->type, sd->tracking_signal_name) == 0 && event->detail1 == 1)
-       {
-               sd->currently_focused = event->source;
-
-               DEBUG("->->->->->-> WIDGET GAINED HIGHLIGHT: %s <-<-<-<-<-<-<-",
-                               atspi_accessible_get_name(sd->currently_focused, NULL));
-
-               sd->description_text = atspi_accessible_get_description(sd->currently_focused, NULL);
-               if(strcmp(sd->description_text, "\0") == 0)
-               {
-                       sd->description_text = atspi_accessible_get_name(sd->currently_focused, NULL);
-                       if(strcmp(sd->description_text, "\0") == 0)
-                               sd->description_text = (char*)atspi_accessible_get_role_name(sd->currently_focused, NULL);
-               }
-               sd->text_to_say_text = get_text_to_read("on_focus", sd->currently_focused);
-               spi_prepare_text(sd);
-       }
-
-       DEBUG("END");
+    DEBUG("START");
+    DEBUG("STATE CHANGED");
+    Service_Data *sd = user_data;
+    char *text_to_read;
+
+    display_info(event);
+    if(strcmp(event->type, sd->tracking_signal_name) == 0 && event->detail1 == 1)
+      {
+         sd->currently_focused = event->source;
+
+         DEBUG("->->->->->-> WIDGET GAINED HIGHLIGHT: %s <-<-<-<-<-<-<-",
+                atspi_accessible_get_name(sd->currently_focused, NULL));
+
+         if(asprintf(&text_to_read, "%s", (char*)atspi_accessible_get_description(sd->currently_focused, NULL)) < 0)
+           {
+              ERROR(MEMORY_ERROR);
+              return;
+           }
+         else if(strcmp(text_to_read, "\0") == 0)
+           {
+              if(asprintf(&text_to_read, "%s", (char*)atspi_accessible_get_name(sd->currently_focused, NULL)) < 0)
+                {
+                   ERROR(MEMORY_ERROR);
+                   return;
+                }
+              else if(strcmp(text_to_read, "\0") == 0)
+                {
+                   if(asprintf(&text_to_read, "%s", (char*)atspi_accessible_get_role_name(sd->currently_focused, NULL)) < 0)
+                     {
+                        ERROR(MEMORY_ERROR);
+                        return;
+                     }
+                }
+           }
+         tts_speak(text_to_read, EINA_FALSE);
+         free(text_to_read);
+      }
+
+    DEBUG("END");
 }
 
+/**
+  * @brief Atspi caret-moved callback passing text to TTS
+  *
+  * @param AtspiEvent instance
+  * @param user_data screen-reader internal data
+  *
+**/
 void spi_on_caret_move_cb(const AtspiEvent *event, void *user_data)
 {
-       DEBUG("START");
-       DEBUG("CARET MOVED");
-       Service_Data *sd = user_data;
-       int char_count;
-       gint caret_pos;
-       char buf[256];
-
-       display_info(event);
-       if(strcmp(event->type, CARET_MOVED_SIG) == 0)
-       {
-               sd->currently_focused = event->source;
-
-               AtspiText *text_interface = atspi_accessible_get_text(sd->currently_focused);
-               if(text_interface)
-               {
-                       DEBUG("->->->->->-> WIDGET CARET MOVED: %s <-<-<-<-<-<-<-",
-                                atspi_accessible_get_name(sd->currently_focused, NULL));
-
-                       char_count = (int)atspi_text_get_character_count(text_interface, NULL);
-                       caret_pos = atspi_text_get_caret_offset(text_interface, NULL);
-                       if(!caret_pos)
-                       {
-                               DEBUG("MIN POSITION REACHED");
-                               sprintf(buf, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MIN_POS_REACHED);
-                       }
-                       else if(char_count == caret_pos)
-                       {
-                               DEBUG("MAX POSITION REACHED");
-                               sprintf(buf, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MAX_POS_REACHED);
-                       }
-                       else
-                               sprintf(buf, "%s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL));
-
-                       sd->text_to_say_text = strdup(buf);
-                       spi_prepare_text(sd);
-               }
-       }
-
-       DEBUG("END");
+    DEBUG("START");
+    DEBUG("CARET MOVED");
+    Service_Data *sd = user_data;
+    int char_count;
+    gint caret_pos;
+    char *text_to_read;
+
+    display_info(event);
+    if(strcmp(event->type, CARET_MOVED_SIG) == 0)
+      {
+         sd->currently_focused = event->source;
+
+         AtspiText *text_interface = atspi_accessible_get_text(sd->currently_focused);
+         if(text_interface)
+           {
+              DEBUG("->->->->->-> WIDGET CARET MOVED: %s <-<-<-<-<-<-<-",
+                    atspi_accessible_get_name(sd->currently_focused, NULL));
+
+              char_count = (int)atspi_text_get_character_count(text_interface, NULL);
+              caret_pos = atspi_text_get_caret_offset(text_interface, NULL);
+              if(!caret_pos)
+                {
+                   DEBUG("MIN POSITION REACHED");
+                   if(asprintf(&text_to_read, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MIN_POS_REACHED) < 0)
+                     {
+                        ERROR(MEMORY_ERROR);
+                        return;
+                     }
+                }
+             else if(char_count == caret_pos)
+               {
+                  DEBUG("MAX POSITION REACHED");
+                  if(asprintf(&text_to_read, "%s %s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL), MAX_POS_REACHED) < 0)
+                    {
+                       ERROR(MEMORY_ERROR);
+                       return;
+                    }
+               }
+             else
+               {
+                  if(asprintf(&text_to_read, "%s", (char*)atspi_text_get_text(text_interface, caret_pos, caret_pos + 1, NULL)))
+                    {
+                      ERROR(MEMORY_ERROR);
+                      return;
+                    }
+               }
+           }
+         else
+           {
+              ERROR(MEMORY_ERROR);
+              return;
+           }
+         tts_speak(text_to_read, EINA_FALSE);
+         free(text_to_read);
+      }
+
+    DEBUG("END");
 }
 
+/**
+  * @brief Atspi value-changed callback passing text to TTS
+  *
+  * @param AtspiEvent instance
+  * @param user_data screen-reader internal data
+  *
+**/
 void spi_on_access_value_changed_cb(const AtspiEvent *event, void *user_data)
 {
-       DEBUG("START");
-       DEBUG("STATE CHANGED");
-       Service_Data *sd = user_data;
-       double current_temp_value;
-       char buf[256];
-
-       display_info(event);
-       if(strcmp(event->type, VALUE_CHANGED_SIG) == 0)
-       {
-               sd->currently_focused = event->source;
-
-               AtspiValue *value_interface = atspi_accessible_get_value(sd->currently_focused);
-               if(value_interface)
-               {
-                       DEBUG("->->->->->-> WIDGET VALUE CHANGED: %s <-<-<-<-<-<-<-",
-                                atspi_accessible_get_name(sd->currently_focused, NULL));
-
-                       current_temp_value = (double)atspi_value_get_current_value(value_interface, NULL);
-                       if(current_temp_value == atspi_value_get_maximum_value(value_interface, NULL))
-                       {
-                               DEBUG("MAX VALUE REACHED");
-                               sprintf(buf, "%.2f %s", current_temp_value, MAX_REACHED);
-                       }
-                       else if(current_temp_value == atspi_value_get_minimum_value(value_interface, NULL))
-                       {
-                               DEBUG("MIN VALUE REACHED");
-                               sprintf(buf, "%.2f %s", current_temp_value, MIN_REACHED);
-                       }
-                       else
-                               sprintf(buf, "%.2f", current_temp_value);
-
-                       sd->text_to_say_text = strdup(buf);
-                       spi_prepare_text(sd);
-               }
-       }
-       DEBUG("END");
+    DEBUG("START");
+    DEBUG("STATE CHANGED");
+    Service_Data *sd = user_data;
+    double current_temp_value;
+    char *text_to_read;
+    float epsilon = 0.000000001;
+
+    display_info(event);
+    if(strcmp(event->type, VALUE_CHANGED_SIG) == 0)
+      {
+         sd->currently_focused = event->source;
+
+         AtspiValue *value_interface = atspi_accessible_get_value(sd->currently_focused);
+         if(value_interface)
+           {
+              DEBUG("->->->->->-> WIDGET VALUE CHANGED: %s <-<-<-<-<-<-<-",
+                    atspi_accessible_get_name(sd->currently_focused, NULL));
+
+              current_temp_value = (double)atspi_value_get_current_value(value_interface, NULL);
+              if(abs(current_temp_value - atspi_value_get_maximum_value(value_interface, NULL)) < epsilon)
+                {
+                   DEBUG("MAX VALUE REACHED");
+                   if(asprintf(&text_to_read, "%.2f %s", current_temp_value, MAX_REACHED) < 0)
+                     {
+                        ERROR(MEMORY_ERROR);
+                        return;
+                     }
+                }
+              else if(abs(current_temp_value - atspi_value_get_minimum_value(value_interface, NULL)) < epsilon)
+                {
+                   DEBUG("MIN VALUE REACHED");
+                   if(asprintf(&text_to_read, "%.2f %s", current_temp_value, MIN_REACHED) < 0)
+                     {
+                        ERROR(MEMORY_ERROR);
+                        return;
+                     }
+                }
+              else
+                {
+                   if(asprintf(&text_to_read, "%.2f", current_temp_value) < 0)
+                     {
+                        ERROR(MEMORY_ERROR);
+                        return;
+                     }
+                }
+           }
+         else
+           {
+              ERROR(MEMORY_ERROR);
+              return;
+           }
+         tts_speak(text_to_read, EINA_FALSE);
+         free(text_to_read);
+      }
+    DEBUG("END");
 }
 
+/**
+  * @brief Initializer for screen-reader atspi listeners
+  *
+  * @param user_data screen-reader internal data
+  *
+**/
 void spi_init(Service_Data *sd)
 {
 
-       DEBUG( "--------------------- SPI_init START ---------------------");
-       service_data = sd;
-
-       DEBUG( ">>> Creating listeners <<<");
-
-       sd->state_changed_listener = atspi_event_listener_new(spi_on_state_changed_cb, service_data, NULL);
-       if(sd->state_changed_listener == NULL)
-       {
-               DEBUG("FAILED TO CREATE spi state changed listener")
-       }
-
-       sd->caret_moved_listener = atspi_event_listener_new(spi_on_caret_move_cb, service_data, NULL);
-       if(sd->caret_moved_listener == NULL)
-       {
-               DEBUG("FAILED TO CREATE spi state changed listener")
-       }
-
-       sd->value_changed_listener = atspi_event_listener_new(spi_on_access_value_changed_cb, service_data, NULL);
-       if(sd->value_changed_listener == NULL)
-       {
-               DEBUG("FAILED TO CREATE spi state changed listener")
-       }
-
-       // ---------------------------------------------------------------------------------------------------
-
-       gboolean ret1 = atspi_event_listener_register(sd->state_changed_listener, sd->tracking_signal_name, NULL);
-       if(ret1 == false)
-       {
-               DEBUG("FAILED TO REGISTER spi focus/highlight listener");
-       }
-
-       gboolean ret2 = atspi_event_listener_register(sd->caret_moved_listener, CARET_MOVED_SIG, NULL);
-       if(ret2 == false)
-       {
-               DEBUG("FAILED TO REGISTER spi caret moved listener");
-       }
-
-       gboolean ret3 = atspi_event_listener_register(sd->value_changed_listener, VALUE_CHANGED_SIG, NULL);
-       if(ret3 == false)
-       {
-               DEBUG("FAILED TO REGISTER spi value changed listener");
-       }
-
-       if(ret1 == true && ret2 == true && ret3 == true)
-       {
-               DEBUG("spi listener REGISTERED");
-       }
-
-       DEBUG( "---------------------- SPI_init END ----------------------\n\n");
+    DEBUG( "--------------------- SPI_init START ---------------------");
+    service_data = sd;
+
+    DEBUG( ">>> Creating listeners <<<");
+
+    sd->state_changed_listener = atspi_event_listener_new(spi_on_state_changed_cb, service_data, NULL);
+    if(sd->state_changed_listener == NULL)
+      {
+         DEBUG("FAILED TO CREATE spi state changed listener")
+      }
+
+    sd->caret_moved_listener = atspi_event_listener_new(spi_on_caret_move_cb, service_data, NULL);
+    if(sd->caret_moved_listener == NULL)
+      {
+         DEBUG("FAILED TO CREATE spi state changed listener")
+      }
+
+    sd->value_changed_listener = atspi_event_listener_new(spi_on_access_value_changed_cb, service_data, NULL);
+    if(sd->value_changed_listener == NULL)
+      {
+         DEBUG("FAILED TO CREATE spi state changed listener")
+      }
+
+    // ---------------------------------------------------------------------------------------------------
+
+    gboolean ret1 = atspi_event_listener_register(sd->state_changed_listener, sd->tracking_signal_name, NULL);
+    if(ret1 == false)
+      {
+         DEBUG("FAILED TO REGISTER spi focus/highlight listener");
+      }
+
+    gboolean ret2 = atspi_event_listener_register(sd->caret_moved_listener, CARET_MOVED_SIG, NULL);
+    if(ret2 == false)
+      {
+         DEBUG("FAILED TO REGISTER spi caret moved listener");
+      }
+
+    gboolean ret3 = atspi_event_listener_register(sd->value_changed_listener, VALUE_CHANGED_SIG, NULL);
+    if(ret3 == false)
+      {
+         DEBUG("FAILED TO REGISTER spi value changed listener");
+      }
+
+    if(ret1 == true && ret2 == true && ret3 == true)
+      {
+         DEBUG("spi listener REGISTERED");
+      }
+
+    DEBUG( "---------------------- SPI_init END ----------------------\n\n");
 }
diff --git a/src/screen_reader_system.c b/src/screen_reader_system.c
new file mode 100644 (file)
index 0000000..b18201c
--- /dev/null
@@ -0,0 +1,113 @@
+#include <device/battery.h>
+#include <device/display.h>
+#include <device/callback.h>
+#include "screen_reader.h"
+#include "screen_reader_tts.h"
+#include "smart_notification.h"
+
+#define CHARGING "Battery charger connected"
+#define NOT_CHARGING "Battery charger disconnected"
+#define SCREEN_ON "Screen is on"
+#define SCREEN_OFF "Screen is off"
+#define BATTERY_LOW "Battery level is low"
+#define BATTERY_FULL "Battery level is full"
+#define BATTERY_CRITICAL "Battery level is critical"
+
+static void device_system_cb(device_callback_e type, void *value, void *user_data);
+
+/**
+ * @brief Initializer for smart notifications
+ *
+ */
+void system_notifications_init(void)
+{
+    // BATTERY LOW/FULL
+    device_add_callback(DEVICE_CALLBACK_BATTERY_LEVEL, device_system_cb, NULL);
+    // BATTERY CHARGING/NOT-CHARGING
+    device_add_callback(DEVICE_CALLBACK_BATTERY_CHARGING, device_system_cb, NULL);
+    // SCREEN OFF/ON
+    device_add_callback(DEVICE_CALLBACK_DISPLAY_STATE, device_system_cb, NULL);
+}
+
+/**
+ * @brief Initializer for smart notifications
+ *
+ */
+void system_notifications_shutdown(void)
+{
+    // BATTERY LOW/FULL
+    device_remove_callback(DEVICE_CALLBACK_BATTERY_LEVEL, device_system_cb);
+    // BATTERY CHARGING/NOT-CHARGING
+    device_remove_callback(DEVICE_CALLBACK_BATTERY_CHARGING, device_system_cb);
+    // SCREEN OFF/ON
+    device_remove_callback(DEVICE_CALLBACK_DISPLAY_STATE, device_system_cb);
+}
+
+/**
+ * @brief Device system callback handler
+ *
+ * @param type Device callback type
+ * @param value UNUSED
+ * @param user_data UNUSED
+ */
+static void device_system_cb(device_callback_e type, void *value, void *user_data)
+{
+    if(type == DEVICE_CALLBACK_BATTERY_LEVEL)
+      {
+         device_battery_level_e status;
+         if(device_battery_get_level_status(&status))
+           {
+              ERROR("Cannot get battery level status");
+              return;
+           }
+
+         if(status == DEVICE_BATTERY_LEVEL_LOW)
+           {
+              tts_speak(BATTERY_LOW, EINA_TRUE);
+           }
+         else if(status == DEVICE_BATTERY_LEVEL_CRITICAL)
+           {
+              tts_speak(BATTERY_CRITICAL, EINA_TRUE);
+           }
+         else if(status == DEVICE_BATTERY_LEVEL_FULL)
+           {
+              tts_speak(BATTERY_FULL, EINA_TRUE);
+           }
+      }
+    else if(type == DEVICE_CALLBACK_BATTERY_CHARGING)
+      {
+         bool charging;
+         if(device_battery_is_charging(&charging))
+           {
+              ERROR("Cannot check if battery is charging");
+              return;
+           }
+
+         if(charging)
+           {
+              tts_speak(CHARGING, EINA_FALSE);
+           }
+         else
+           {
+              tts_speak(NOT_CHARGING, EINA_FALSE);
+           }
+      }
+    else if(type == DEVICE_CALLBACK_DISPLAY_STATE)
+      {
+         display_state_e state;
+         if(device_display_get_state(&state))
+           {
+              ERROR("Cannot check if battery is charging");
+              return;
+           }
+
+         if(state == DISPLAY_STATE_NORMAL)
+           {
+              tts_speak(SCREEN_ON, EINA_FALSE);
+           }
+         else if(state == DISPLAY_STATE_SCREEN_OFF)
+           {
+              tts_speak(SCREEN_OFF, EINA_FALSE);
+           }
+      }
+}
index a9b032a..4701afb 100644 (file)
 /*
- * screen_reader_tts.c
- *
- *  Created on: Feb 19, 2014
- *  Author: m.skorupinsk
- */
+* screen_reader_tts.c
+*
+*  Created on: Feb 19, 2014
+*  Author: m.skorupinsk
+*/
+#define _GNU_SOURCE
+
 #include <Ecore.h>
 #include "screen_reader_tts.h"
 #include "logger.h"
 
 // ---------------------------- DEBUG HELPERS ------------------------------
 
+#define FLUSH_LIMIT 1
+
+static int last_utt_id;
+static Eina_Bool pause_state = EINA_FALSE;
+static Eina_Bool flush_flag = EINA_FALSE;
+
 static char * get_tts_error( int r )
 {
-       switch( r )
-       {
-               case TTS_ERROR_NONE:
-               {
-                       return "no error";
-               }
-               case TTS_ERROR_INVALID_PARAMETER:
-               {
-                       return "inv param";
-               }
-               case TTS_ERROR_OUT_OF_MEMORY:
-               {
-                       return "out of memory";
-               }
-               case TTS_ERROR_OPERATION_FAILED:
-               {
-                       return "oper failed";
-               }
-               case TTS_ERROR_INVALID_STATE:
-               {
-                       return "inv state";
-               }
-               default:
-               {
-                       return "inny error";
-               }
-       }
+    switch( r )
+      {
+         case TTS_ERROR_NONE:
+           {
+              return "no error";
+           }
+         case TTS_ERROR_INVALID_PARAMETER:
+           {
+              return "inv param";
+           }
+         case TTS_ERROR_OUT_OF_MEMORY:
+           {
+              return "out of memory";
+           }
+         case TTS_ERROR_OPERATION_FAILED:
+           {
+              return "oper failed";
+           }
+         case TTS_ERROR_INVALID_STATE:
+           {
+              return "inv state";
+           }
+         default:
+           {
+              return "uknown error";
+           }
+      }
 }
 
 static char * get_tts_state( tts_state_e r )
 {
-       switch( r )
-       {
-               case TTS_STATE_CREATED:
-               {
-                       return "created";
-               }
-               case TTS_STATE_READY:
-               {
-                       return "ready";
-               }
-               case TTS_STATE_PLAYING:
-               {
-                       return "playing";
-               }
-               case TTS_STATE_PAUSED:
-               {
-                       return "pause";
-               }
-               default:
-               {
-                       return "uknown state";
-               }
-       }
+    switch( r )
+      {
+         case TTS_STATE_CREATED:
+           {
+              return "created";
+           }
+         case TTS_STATE_READY:
+           {
+              return "ready";
+           }
+         case TTS_STATE_PLAYING:
+           {
+              return "playing";
+           }
+         case TTS_STATE_PAUSED:
+           {
+              return "pause";
+           }
+         default:
+           {
+              return "uknown state";
+           }
+      }
 }
 
-// -------------------------------------------------------------------------------------------------
+//-------------------------------------------------------------------------------------------------
 
 bool get_supported_voices_cb(tts_h tts, const char* language, int voice_type, void* user_data)
 {
-       DEBUG("LANG: %s; TYPE: %d", language, voice_type);
+    DEBUG("LANG: %s; TYPE: %d", language, voice_type);
 
-       Service_Data *sd = user_data;
-       Voice_Info *vi = calloc(1, sizeof(Voice_Info));
+    Service_Data *sd = user_data;
+    Voice_Info *vi = calloc(1, sizeof(Voice_Info));
 
-       int len = strlen(language);
+    if(asprintf(&vi->language, "%s",language) < 0)
+      {
+         ERROR(MEMORY_ERROR);
+         return  ECORE_CALLBACK_CANCEL;
+      }
 
-       vi->language = calloc(len + 1, sizeof(char));
-       strcpy(vi->language, language);
+    vi->voice_type = voice_type;
 
-       vi->voice_type = voice_type;
+    sd->available_languages = eina_list_append(sd->available_languages, vi);
 
-       sd->available_languages = eina_list_append(sd->available_languages, vi);
-
-       return ECORE_CALLBACK_RENEW;
+    return ECORE_CALLBACK_RENEW;
 }
 
 static void __tts_test_utt_started_cb(tts_h tts, int utt_id, void* user_data)
 {
-       DEBUG("Utterance started : utt id(%d) \n", utt_id);
-
-       return;
+    DEBUG("Utterance started : utt id(%d) \n", utt_id);
+    return;
 }
 
 static void __tts_test_utt_completed_cb(tts_h tts, int utt_id, void* user_data)
 {
-       DEBUG("Utterance completed : utt id(%d) \n", utt_id);
-
-       return;
+    DEBUG("Utterance completed : utt id(%d) \n", utt_id);
+    if(last_utt_id - utt_id > FLUSH_LIMIT)
+       flush_flag = EINA_TRUE;
+    else
+      {
+         if(flush_flag)
+            flush_flag = EINA_FALSE;
+      }
+    return;
 }
 
 bool tts_init(void *data)
 {
-       DEBUG( "--------------------- TTS_init START ---------------------");
-       Service_Data *sd = data;
+    DEBUG( "--------------------- TTS_init START ---------------------");
+    Service_Data *sd = data;
+
+    int r = tts_create( &sd->tts );
+    DEBUG( "Create tts %d (%s)", r, get_tts_error( r ) );
 
-       int r = tts_create( &sd->tts );
-       DEBUG( "Create tts %d (%s)", r, get_tts_error( r ) );
+    r = tts_set_mode( sd->tts, TTS_MODE_DEFAULT );
+    DEBUG( "Set tts mode SR %d (%s)", r, get_tts_error( r ) );
 
-       r = tts_set_mode( sd->tts, TTS_MODE_DEFAULT );
-       DEBUG( "Set tts mode SR %d (%s)", r, get_tts_error( r ) );
+    r = tts_prepare( sd->tts );
+    DEBUG( "Prepare tts %d (%s)", r, get_tts_error( r ) );
 
-       r = tts_prepare( sd->tts );
-       DEBUG( "Prepare tts %d (%s)", r, get_tts_error( r ) );
+    tts_set_state_changed_cb(sd->tts, state_changed_cb, sd);
 
-       tts_set_state_changed_cb(sd->tts, state_changed_cb, sd);
+    tts_set_utterance_started_cb(sd->tts, __tts_test_utt_started_cb, sd);
+    tts_set_utterance_completed_cb( sd->tts,  __tts_test_utt_completed_cb,  sd);
 
-       tts_set_utterance_started_cb(sd->tts, __tts_test_utt_started_cb, sd);
-       tts_set_utterance_completed_cb( sd->tts,  __tts_test_utt_completed_cb,  sd);
+    DEBUG( "---------------------- TTS_init END ----------------------\n\n");
+    return true;
+}
 
-       DEBUG( "---------------------- TTS_init END ----------------------\n\n");
-       return true;
+Eina_Bool tts_pause_set(Eina_Bool pause_switch)
+{
+    Service_Data *sd = get_pointer_to_service_data_struct();
+    if(!sd)
+       return EINA_FALSE;
+
+    if(pause_switch)
+      {
+         if(!tts_pause(sd->tts))
+            pause_state = EINA_TRUE;
+         else
+            return EINA_FALSE;
+      }
+    else if(!pause_switch)
+      {
+         if(!tts_play(sd->tts))
+            pause_state = EINA_FALSE;
+         else
+            return EINA_FALSE;
+      }
+    return EINA_TRUE;
 }
 
-Eina_Bool tts_speak( void * data )
+Eina_Bool tts_speak(char *text_to_speak, Eina_Bool flush_switch)
 {
-       Service_Data *sd = data;
-       int speak_id;
-       const char * text_to_speak = NULL;
+    Service_Data *sd = get_pointer_to_service_data_struct();
+    int speak_id;
 
-       if (sd->_dbus_txt_readed == 0 && sd->text_from_dbus ) {
-               text_to_speak = sd->text_from_dbus;
-               sd->_dbus_txt_readed = 1;
-       }
-       else
-               text_to_speak = sd->text_to_say_text;
+    if(!sd)
+       return EINA_FALSE;
 
-       DEBUG( "tts_speak\n");
-       DEBUG( "text to say:%s\n", text_to_speak);
-       if ( !text_to_speak ) return EINA_FALSE;
-       if ( !text_to_speak[0] ) return EINA_FALSE;
+    if(flush_flag || flush_switch)
+       tts_stop(sd->tts);
 
-       tts_add_text( sd->tts, text_to_speak, NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &speak_id );
-       DEBUG("added id to:%d\n", speak_id);
+    DEBUG( "tts_speak\n");
+    DEBUG( "text to say:%s\n", text_to_speak);
+    if ( !text_to_speak ) return EINA_FALSE;
+    if ( !text_to_speak[0] ) return EINA_FALSE;
 
-       tts_play( sd->tts );
-       return EINA_FALSE;
+    if(tts_add_text( sd->tts, text_to_speak, sd->language, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &speak_id))
+       return EINA_FALSE;
 
-}
+    DEBUG("added id to:%d\n", speak_id);
+    last_utt_id = speak_id;
 
-bool update_supported_voices(void *data)
-{
-       DEBUG("START");
-       tts_state_e state;
-
-       Service_Data *sd = data;
-
-       int res = tts_get_state(sd->tts, &state);
-
-       if(res != TTS_ERROR_NONE)
-       {
-               DEBUG("CANNOT RETRIVE STATE");
-               return false;
-       }
-
-       if(state == TTS_STATE_READY)
-       {
-               tts_foreach_supported_voices(sd->tts, get_supported_voices_cb, sd);
-       }
-       else
-       {
-               sd->update_language_list = true;
-       }
-
-       DEBUG("END")
-       return true;
+    return EINA_TRUE;
 }
 
-void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data)
+Eina_Bool update_supported_voices(void *data)
 {
-       DEBUG("++++++++++++++++state_changed_cb\n++++++++++++++++++");
-       DEBUG("current state:%s and previous state:%s\n", get_tts_state(current), get_tts_state(previous));
-       Service_Data *sd = user_data;
-
-       if(current == TTS_STATE_READY) {
-               DEBUG("State is ready after prepare\n");
-               tts_speak(sd);
-       }
+    DEBUG("START");
+    tts_state_e state;
+
+    Service_Data *sd = data;
+
+    int res = tts_get_state(sd->tts, &state);
+
+    if(res != TTS_ERROR_NONE)
+      {
+         DEBUG("CANNOT RETRIVE STATE");
+         return EINA_FALSE;
+      }
+
+    if(state == TTS_STATE_READY)
+      {
+         tts_foreach_supported_voices(sd->tts, get_supported_voices_cb, sd);
+      }
     else
-    {
-        DEBUG("State is diffrent then ready after prepare!\n");
-    }
-}
+      {
+         sd->update_language_list = EINA_TRUE;
+      }
 
-void spi_prepare_text(void *data)
-{
-       Service_Data *sd = data;
-       sd->say_text = true;
-       sd->update_language_list = false;
-    DEBUG("PREPARE TEXT!!!!!!!!!!!!!!\n");
-        
-    tts_stop(sd->tts);
-    tts_append_text(sd);
+    DEBUG("END")
+    return EINA_TRUE;
 }
 
-void tts_append_text(void *data)
+void state_changed_cb(tts_h tts, tts_state_e previous, tts_state_e current, void* user_data)
 {
-       Service_Data *sd = data;
-       tts_state_e state;
-       tts_get_state(sd->tts, &state);
-
-       DEBUG("text append:::!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
-       if(state == TTS_STATE_READY)
-       {
-        DEBUG("TTS state == ready!\n");
-               tts_speak(data);
-       }
+    if(pause_state)
+      {
+         DEBUG("TTS is currently paused. Resume to start reading");
+         return;
+      }
+
+    DEBUG("++++++++++++++++state_changed_cb\n++++++++++++++++++");
+    DEBUG("current state:%s and previous state:%s\n", get_tts_state(current), get_tts_state(previous));
+    Service_Data *sd = user_data;
+
+    if(current == TTS_STATE_READY || current == TTS_STATE_PAUSED)
+      {
+         DEBUG("TTS state == %s!", get_tts_state(current));
+         tts_play(sd->tts);
+      }
     else
-    {
-        DEBUG("TTS state != ready!\n");
-    }
+      {
+         DEBUG("TTS state != ready or paused!\n");
+      }
 }
 
 void spi_stop( void *data)
 {
-       Service_Data *sd = data;
-       sd->say_text = false;
-       sd->update_language_list = false;
-       free(sd->text_to_say_text);
-       free(sd->description_text);
-       free((char*)sd->text_from_dbus);
-       free(sd->current_value);
-       sd->text_to_say_text = NULL;
-       sd->description_text = NULL;
-       sd->text_from_dbus = NULL;
-       sd->current_value = NULL;
-       tts_stop(sd->tts);
-}
+    Service_Data *sd = data;
+    sd->update_language_list = false;
+    free((char*)sd->text_from_dbus);
+    free(sd->current_value);
+    sd->text_from_dbus = NULL;
+    sd->current_value = NULL;
+    tts_stop(sd->tts);
+}
\ No newline at end of file
index 2349e0e..1561129 100644 (file)
@@ -1,88 +1,82 @@
 /*
- * screen_reader_xml.c
- *
- *  Created on: Mar 26, 2014
- *      Author: m.skorupinsk
- */
+* screen_reader_xml.c
+*
+*  Created on: Mar 26, 2014
+*      Author: m.skorupinsk
+*/
+
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include "logger.h"
+#include "xml_parser.h"
 #include "screen_reader_xml.h"
 
 static Service_Data *service_data;
 
 char *get_text_to_read(const char *action, AtspiAccessible *widget)
 {
-       char *description = service_data->description_text;
-
-       DEBUG("DESCRIPTION %s\n", description);
-
-       if(description == NULL)
-       {
-               DEBUG("NULL DESCRIPTION\n");
-               return NULL;
-       }
-       else if(description[0] == 0)
-       {
-               DEBUG("DESCRIPTION[0] = 0\n");
-               return NULL;
-       }
-
-       int level = service_data->information_level;
-
-       Eina_Simple_XML_Attribute *attributes[2] = {NULL, NULL};
-
-       char level_str[2];
-       snprintf(level_str, 2, "%d", level);
-
-       DEBUG("THE LEVEL STRING: %s LEVEL: %d\n", level_str, level);
-
-       attributes[0] = eina_simple_xml_attribute_new(NULL, "level", level_str);
-
-       char *ret_str;
-       char *tmp = get_string_str(NULL, description, attributes, "Information_Level");
-       eina_simple_xml_attribute_free(attributes[0]);
-
-       AtspiStateSet *state_set = atspi_accessible_get_state_set (widget);
-       AtspiStateType state =  ATSPI_STATE_ENABLED;
-       gboolean bstate = atspi_state_set_contains(state_set, state);
-
-       g_object_unref(state_set);
-
-       if(!bstate)
-         {
-           const char *string_is_disable = "is disabled";
-           GError *err = NULL;
-           int ret_str_size;
-           int cnt;
-
-           ret_str_size = strlen(tmp) + strlen(string_is_disable) + 1;/* offset for spaces */
-           ret_str = malloc(ret_str_size);
-           if(!ret_str)
-             {
-               ERROR("Failed to allocate memory");
-               free(tmp);
-               return NULL;
-             }
-           /* example push_button BLUE is disabled */
-           cnt = snprintf(ret_str, ret_str_size, "%s %s", tmp, string_is_disable);
-           free(tmp);
-           if (cnt < ret_str_size)/* Buffer should be of expected size and this also checks for -1 error */
-             {
-               ERROR("Failed to format buffer...");
-               ERROR("Buffer[%d/%d][%s]", cnt, ret_str_size, ret_str);
-               free(ret_str);
-               return NULL;
-             }
-         }
-        else
-          ret_str = tmp;
-
-       DEBUG("\n\n-> -> -> THE STRING TO SAY: <- <- <- \n%s\n\n", ret_str);
-
-       return ret_str;
+    char *description = NULL;
+
+    DEBUG("DESCRIPTION %s\n", description);
+
+    if(description == NULL)
+      {
+         DEBUG("NULL DESCRIPTION\n");
+         return NULL;
+      }
+    else if(description[0] == 0)
+      {
+         DEBUG("DESCRIPTION[0] = 0\n");
+         return NULL;
+      }
+
+    int level = service_data->information_level;
+
+    Eina_Simple_XML_Attribute *attributes[2] = {NULL, NULL};
+
+    char *level_str;
+    if(asprintf(&level_str, "%d", level) < 0)
+      {
+         ERROR("Failed to allocate memory...");
+         return NULL;
+      }
+
+    DEBUG("THE LEVEL STRING: %s LEVEL: %d\n", level_str, level);
+
+    attributes[0] = eina_simple_xml_attribute_new(NULL, "level", level_str);
+    free(level_str);
+
+    char *ret_str;
+    char *tmp = get_string_str(NULL, description, attributes, "Information_Level");
+    eina_simple_xml_attribute_free(attributes[0]);
+
+    AtspiStateSet *state_set = atspi_accessible_get_state_set (widget);
+    AtspiStateType state =  ATSPI_STATE_ENABLED;
+    gboolean bstate = atspi_state_set_contains(state_set, state);
+
+    g_object_unref(state_set);
+
+    if(!bstate)
+      {
+         const char *string_is_disable = "is disabled";
+        /* example push_button BLUE is disabled */
+        if(asprintf(&ret_str, "%s %s", tmp, string_is_disable) < 0)
+          {
+             ERROR("Failed to allocate memory");
+             free(tmp);
+             return NULL;
+          }
+        }
+    else
+       ret_str = tmp;
+
+    DEBUG("\n\n-> -> -> THE STRING TO SAY: <- <- <- \n%s\n\n", ret_str);
+    free(tmp);
+    return ret_str;
 }
 
 void xml_init(Service_Data *sd)
 {
-       service_data = sd;
+    service_data = sd;
 }
diff --git a/src/smart_notification.c b/src/smart_notification.c
new file mode 100644 (file)
index 0000000..15a7c5e
--- /dev/null
@@ -0,0 +1,180 @@
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Evas.h>
+#include <atspi/atspi.h>
+#include <tone_player.h>
+#include "logger.h"
+#include "screen_reader_tts.h"
+#include "smart_notification.h"
+
+#define RED  "\x1B[31m"
+#define RESET "\033[0m"
+
+#define ITEMS_NOTIFICATION "Visible items from %d to %d"
+
+static Eina_Bool status = EINA_FALSE;
+
+static void _smart_notification_focus_chain_end(void);
+static void _smart_notification_realized_items(int start_idx, int end_idx);
+
+/**
+ * @brief Smart Notifications event handler
+ *
+ * @param nt Notification event type
+ * @param start_index int first visible items index smart_notification_realized_items
+ * @param end_index int last visible items index used for smart_notification_realized_items
+ */
+void smart_notification(Notification_Type nt, int start_index, int end_index)
+{
+    if(!status)
+        return;
+
+    switch(nt)
+    {
+        case FOCUS_CHAIN_END_NOTIFICATION_EVENT:
+            _smart_notification_focus_chain_end();
+            break;
+        case REALIZED_ITEMS_NOTIFICATION_EVENT:
+            _smart_notification_realized_items(start_index, end_index);
+            break;
+        default:
+            DEBUG("Gesture type %d not handled in switch", nt);
+    }
+}
+
+/**
+ * @brief Used for getting first and last index of visible items
+ *
+ * @param scrollable_object AtspiAccessible object on which scroll was triggered
+ * @param start_index int first visible items index smart_notification_realized_items
+ * @param end_index int last visible items index used for smart_notification_realized_items
+ */
+void get_realized_items_count(AtspiAccessible *scrollable_object, int *start_idx, int *end_idx)
+{
+    int count_child, jdx;
+    AtspiAccessible *child_iter;
+    AtspiStateType state =  ATSPI_STATE_SHOWING;
+
+    if(!scrollable_object)
+      {
+         DEBUG("No scrollable object");
+         return;
+      }
+
+    count_child = atspi_accessible_get_child_count(scrollable_object, NULL);
+
+    for(jdx = 0; jdx < count_child; jdx++)
+    {
+        child_iter = atspi_accessible_get_child_at_index(scrollable_object, jdx, NULL);
+
+        AtspiStateSet* state_set = atspi_accessible_get_state_set(child_iter);
+
+        gboolean is_visible = atspi_state_set_contains(state_set, state);
+        if(is_visible)
+        {
+            *start_idx = jdx;
+            DEBUG("Item with index %d is visible", jdx);
+        }
+        else
+            DEBUG("Item with index %d is NOT visible", jdx);
+    }
+    *end_idx = *start_idx + 8;
+}
+
+/**
+ * @brief Scroll-start/Scroll-end event callback
+ *
+ * @param event AtspiEvent
+ * @param user_data UNUSED
+ */
+static void
+_scroll_event_cb(const AtspiEvent     *event, gpointer user_data)
+{
+   if(!status)
+        return;
+
+   int start_index, end_index;
+   start_index = 0;
+   end_index = 0;
+
+   fprintf(stderr, "Event: %s: %d, obj: %p: role: %s\n", event->type, event->detail1, event->source,
+           atspi_accessible_get_role_name(event->source, NULL));
+
+   if (!strcmp(event->type, "object:scroll-start"))
+     {
+        DEBUG("Scrolling started");
+        tts_speak("Scrolling started", EINA_TRUE);
+     }
+   else if (!strcmp(event->type, "object:scroll-end"))
+     {
+        DEBUG("Scrolling finished");
+        tts_speak("Scrolling finished", EINA_FALSE);
+        get_realized_items_count((AtspiAccessible *)event->source, &start_index, &end_index);
+        _smart_notification_realized_items(start_index, end_index);
+     }
+}
+
+/**
+ * @brief Initializer for smart notifications
+ *
+ *
+ */
+void smart_notification_init(void)
+{
+    DEBUG("Smart Notification init!");
+
+    AtspiEventListener *listener;
+
+    listener = atspi_event_listener_new(_scroll_event_cb, NULL, NULL);
+    atspi_event_listener_register(listener, "object:scroll-start", NULL);
+    atspi_event_listener_register(listener, "object:scroll-end", NULL);
+
+    haptic_module_init();
+
+    status = EINA_TRUE;
+}
+
+/**
+ * @brief Smart notifications shutdown
+ *
+ */
+void smart_notification_shutdown(void)
+{
+    status = EINA_FALSE;
+}
+
+/**
+ * @brief Smart notifications focus chain event handler
+ *
+ */
+static void _smart_notification_focus_chain_end(void)
+{
+    if(!status)
+       return;
+
+    DEBUG(RED"Smart notification - FOCUS CHAIN END"RESET);
+
+    tone_player_stop(0);
+    tone_player_start(TONE_TYPE_SUP_CONFIRM, SOUND_TYPE_MEDIA, 200, NULL);
+}
+
+/**
+ * @brief Smart notifications realized items event handler
+ *
+ */
+static void _smart_notification_realized_items(int start_idx, int end_idx)
+{
+    if(!status)
+       return;
+
+    if(start_idx == end_idx)
+       return;
+
+    DEBUG(RED"Smart notification - Visible items notification"RESET);
+
+    char buf[256];
+
+    sprintf(buf, ITEMS_NOTIFICATION, start_idx, end_idx);
+
+    tts_speak(strdup(buf), EINA_FALSE);
+}