Merge "Add function to generate description from nested object hierarchy" into tizen
[profile/tv/apps/native/screen-reader.git] / src / smart_notification.c
1 #include <atspi/atspi.h>
2 #include <stdio.h>
3 #include "logger.h"
4 #include "screen_reader_tts.h"
5 #include "screen_reader_haptic.h"
6 #include "smart_notification.h"
7
8 #define RED  "\x1B[31m"
9 #define RESET "\033[0m"
10
11 #define ITEMS_NOTIFICATION "Visible items from %d to %d"
12
13 static gboolean status = FALSE;
14
15 static void _smart_notification_focus_chain_end(void);
16 static void _smart_notification_realized_items(int start_idx, int end_idx);
17
18 /**
19  * @brief Smart Notifications event handler
20  *
21  * @param nt Notification event type
22  * @param start_index int first visible items index smart_notification_realized_items
23  * @param end_index int last visible items index used for smart_notification_realized_items
24  */
25 void smart_notification(Notification_Type nt, int start_index, int end_index)
26 {
27     if(!status)
28         return;
29
30     switch(nt)
31     {
32         case FOCUS_CHAIN_END_NOTIFICATION_EVENT:
33             _smart_notification_focus_chain_end();
34             break;
35         case REALIZED_ITEMS_NOTIFICATION_EVENT:
36             _smart_notification_realized_items(start_index, end_index);
37             break;
38         default:
39             DEBUG("Gesture type %d not handled in switch", nt);
40     }
41 }
42
43 /**
44  * @brief Used for getting first and last index of visible items
45  *
46  * @param scrollable_object AtspiAccessible object on which scroll was triggered
47  * @param start_index int first visible items index smart_notification_realized_items
48  * @param end_index int last visible items index used for smart_notification_realized_items
49  */
50 void get_realized_items_count(AtspiAccessible *scrollable_object, int *start_idx, int *end_idx)
51 {
52     int count_child, jdx;
53     AtspiAccessible *child_iter;
54     AtspiStateType state =  ATSPI_STATE_SHOWING;
55
56     if(!scrollable_object)
57       {
58          DEBUG("No scrollable object");
59          return;
60       }
61
62     count_child = atspi_accessible_get_child_count(scrollable_object, NULL);
63
64     for(jdx = 0; jdx < count_child; jdx++)
65     {
66         child_iter = atspi_accessible_get_child_at_index(scrollable_object, jdx, NULL);
67
68         AtspiStateSet* state_set = atspi_accessible_get_state_set(child_iter);
69
70         gboolean is_visible = atspi_state_set_contains(state_set, state);
71         if(is_visible)
72         {
73             *start_idx = jdx;
74             DEBUG("Item with index %d is visible", jdx);
75         }
76         else
77             DEBUG("Item with index %d is NOT visible", jdx);
78     }
79     *end_idx = *start_idx + 8;
80 }
81
82 /**
83  * @brief Scroll-start/Scroll-end event callback
84  *
85  * @param event AtspiEvent
86  * @param user_data UNUSED
87  */
88 static void
89 _scroll_event_cb(AtspiEvent     *event, void *user_data)
90 {
91    if(!status)
92         return;
93
94    int start_index, end_index;
95    start_index = 0;
96    end_index = 0;
97
98    DEBUG("Event: %s: %d, obj: %p: role: %s\n", event->type, event->detail1, event->source,
99          atspi_accessible_get_role_name(event->source, NULL));
100
101    if (!strcmp(event->type, "object:scroll-start"))
102      {
103         DEBUG("Scrolling started");
104         tts_speak("Scrolling started", TRUE);
105      }
106    else if (!strcmp(event->type, "object:scroll-end"))
107      {
108         DEBUG("Scrolling finished");
109         tts_speak("Scrolling finished", FALSE);
110         get_realized_items_count((AtspiAccessible *)event->source, &start_index, &end_index);
111         _smart_notification_realized_items(start_index, end_index);
112      }
113 }
114
115 /**
116  * @brief Initializer for smart notifications
117  *
118  *
119  */
120 void smart_notification_init(void)
121 {
122     DEBUG("Smart Notification init!");
123
124     AtspiEventListener *listener;
125
126     listener = atspi_event_listener_new(_scroll_event_cb, NULL, NULL);
127     atspi_event_listener_register(listener, "object:scroll-start", NULL);
128     atspi_event_listener_register(listener, "object:scroll-end", NULL);
129
130     haptic_module_init();
131
132     status = TRUE;
133 }
134
135 /**
136  * @brief Smart notifications shutdown
137  *
138  */
139 void smart_notification_shutdown(void)
140 {
141     status = FALSE;
142 }
143
144 /**
145  * @brief Smart notifications focus chain event handler
146  *
147  */
148 static void _smart_notification_focus_chain_end(void)
149 {
150     if(!status)
151        return;
152
153     DEBUG(RED"Smart notification - FOCUS CHAIN END"RESET);
154 }
155
156 /**
157  * @brief Smart notifications realized items event handler
158  *
159  */
160 static void _smart_notification_realized_items(int start_idx, int end_idx)
161 {
162     if(!status)
163        return;
164
165     if(start_idx == end_idx)
166        return;
167
168     DEBUG(RED"Smart notification - Visible items notification"RESET);
169
170     char buf[256];
171
172     snprintf(buf, sizeof(buf), ITEMS_NOTIFICATION, start_idx, end_idx);
173
174     tts_speak(strdup(buf), FALSE);
175 }