From 6600f486e1e6f6e6575c56c338a04af5cc40f8fb Mon Sep 17 00:00:00 2001 From: "Geunsun, Lee" Date: Fri, 18 Nov 2016 19:19:44 +0900 Subject: [PATCH] Implement Screen Reader for homscreen Change-Id: I5ceb5774c1dca63700ee3976bf4aaaba24234074 --- inc/apps_view.h | 2 + inc/cluster_page.h | 1 + inc/cluster_view.h | 1 + inc/homescreen-efl.h | 4 + inc/screen_reader_handler.h | 59 ++++++ inc/widget_viewer.h | 3 + src/add_widget_viewer/add_widget_viewer.c | 100 ++++++++- src/apps_view.c | 331 +++++++++++++++++++++++++++++- src/cluster_page.c | 27 +++ src/cluster_view.c | 124 ++++++++++- src/homescreen-efl.c | 66 +++++- src/screen_reader_handler.c | 198 ++++++++++++++++++ src/widget_viewer.c | 16 ++ 13 files changed, 918 insertions(+), 14 deletions(-) create mode 100755 inc/screen_reader_handler.h create mode 100755 src/screen_reader_handler.c diff --git a/inc/apps_view.h b/inc/apps_view.h index 977dee1..80fcc53 100755 --- a/inc/apps_view.h +++ b/inc/apps_view.h @@ -49,4 +49,6 @@ void apps_view_set_state(view_state_t state); void apps_view_update_label(app_data_t *item); void apps_view_lang_changed(homescreen_view_t view_type); +void apps_view_get_access_object_list(Eina_List **list); + #endif /* __APPS_VIEW_H__ */ diff --git a/inc/cluster_page.h b/inc/cluster_page.h index 930fe95..6b914c6 100755 --- a/inc/cluster_page.h +++ b/inc/cluster_page.h @@ -49,5 +49,6 @@ void cluster_page_drag_cancel(cluster_page_t *page); void cluster_page_drag_widget(cluster_page_t *page, widget_size_type_e type, int pos_x, int pos_y); bool cluster_page_drop_widget(cluster_page_t *page, widget_data_t *widget); void cluster_page_get_highlight_xy(cluster_page_t *page, int *x, int *y); +void cluster_page_get_access_widget_list(cluster_page_t *page_t, Eina_List **list, Eina_Bool is_edit); #endif /* __CLUSTER_VIEW_PAGE_H__ */ diff --git a/inc/cluster_view.h b/inc/cluster_view.h index a67b538..3297dd0 100755 --- a/inc/cluster_view.h +++ b/inc/cluster_view.h @@ -42,5 +42,6 @@ bool cluster_view_set_state(view_state_t state); void cluster_view_delete_widget(widget_data_t *item); bool cluster_view_add_widget(widget_data_t *item, bool scroll); void cluster_view_edit_on_done(cluster_page_t *page); +void cluster_view_get_access_object_list(Eina_List **list); #endif /* __CLUSTER_VIEW_H__ */ diff --git a/inc/homescreen-efl.h b/inc/homescreen-efl.h index 8712665..fb41bd9 100755 --- a/inc/homescreen-efl.h +++ b/inc/homescreen-efl.h @@ -44,4 +44,8 @@ void homescreen_efl_hw_back_key_release(void); void homescreen_efl_btn_show(homescreen_view_t view_t); void homescreen_efl_btn_hide(homescreen_view_t view_t); +void homescreen_efl_get_access_menu_btn(Eina_List **list); +void homescreen_efl_get_access_apps_btn(Eina_List **list); +void homescreen_efl_get_access_home_btn(Eina_List **list); + #endif /* __HOMESCREEN_EFL_H__ */ diff --git a/inc/screen_reader_handler.h b/inc/screen_reader_handler.h new file mode 100755 index 0000000..fdae94d --- /dev/null +++ b/inc/screen_reader_handler.h @@ -0,0 +1,59 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SCREEN_READER_HANDLER_H__ +#define __SCREEN_READER_HANDLER_H__ + +#include + +typedef enum { + INIT_TYPE, + CLEAR, + HOME, + ADD_VIEWER, + WALLPAPER, + APPS +} screen_reader_t; + +typedef struct { + Eina_Bool is_access_obj; + Evas_Object *target; + Evas_Object *parent; + char *name; + char *description; + Elm_Atspi_Role role; + int priority; + void (*clicked_cb)(void *data, Evas_Object *obj, const char *emission, const char *source); + void *cb_data; +} access_info_t; + +#define ACCESS_PRIORITY_CHOOSER_LABEL -30 +#define ACCESS_PRIORITY_CHOOSER_CANCEL -20 +#define ACCESS_PRIORITY_CHOOSER_DONE -10 +#define ACCESS_PRIORITY_WIDGET 10 +#define ACCESS_PRIORITY_MENUBUTTON 10000000 +#define ACCESS_PRIORITY_APPSBUTTON 20000000 +#define ACCESS_PRIORITY_HOMEBUTTON 20000010 +#define ACCESS_PRIORITY_ALL_PAGE 100 +#define ACCESS_PRIORITY_APP_ICON 10 +#define ACCESS_PRIORITY_FOLDER_TITLE 1 + +void screen_reader_update(screen_reader_t type); +void screen_reader_read(char *str); +void screen_reader_update_name(Evas_Object *target_obj, const char *name); +void screen_reader_update_description(Evas_Object *target_obj, const char *description); + +#endif /* __SCREEN_READER_HANDLER_H__ */ diff --git a/inc/widget_viewer.h b/inc/widget_viewer.h index 75d7876..59cad07 100755 --- a/inc/widget_viewer.h +++ b/inc/widget_viewer.h @@ -22,6 +22,7 @@ #include #include "cluster_data.h" +#include "screen_reader_handler.h" void widget_viewer_init(Evas_Object *win); void widget_viewer_fini(void); @@ -34,4 +35,6 @@ void widget_viewer_thumbnail_delete(widget_data_t *item); void widget_viewer_pause_widget(widget_data_t *widget_data); void widget_viewer_resume_widget(widget_data_t *widget_data); +access_info_t *widget_viewer_get_accessible_delete_btn(widget_data_t *widget_data); + #endif /* __WIDGET_VIEWER_H__ */ diff --git a/src/add_widget_viewer/add_widget_viewer.c b/src/add_widget_viewer/add_widget_viewer.c index 881ce92..4354e82 100755 --- a/src/add_widget_viewer/add_widget_viewer.c +++ b/src/add_widget_viewer/add_widget_viewer.c @@ -26,6 +26,8 @@ #include "util.h" #include "conf.h" #include "edc_conf.h" +#include "screen_reader_handler.h" + static struct { Evas_Object *win; @@ -65,6 +67,7 @@ static void __add_widget_viewer_preview_clicked_cb(void *data, Evas_Object *obj, static Evas_Object *__add_widget_viewer_list_widget_preview_box_create(Evas_Object *main_box, add_widget_data_t *widget, add_widget_data_preview_t *preview); static void __add_widget_viewer_item_realized_cb(void *data, Evas_Object *obj, void *event_info); static i18n_uchar __add_widget_viewer_get_first_char_from_hangul(const char *index); +static void __add_widget_get_size_by_type(int type, int *w, int *h); void add_widget_viewer_win_create(void) { @@ -154,7 +157,7 @@ static Evas_Object *__add_widget_viewer_create_conformant(void) return conformant; } -static Evas_Object *__add_widget_viewer_create_layout() +static Evas_Object *__add_widget_viewer_create_layout(void) { Evas_Object *layout; char edj_path[STR_PATH_LEN] = {0, }; @@ -179,7 +182,7 @@ static Evas_Object *__add_widget_viewer_create_layout() return layout; } -static Evas_Object *__add_widget_viewer_create_naviframe() +static Evas_Object *__add_widget_viewer_create_naviframe(void) { Evas_Object *naviframe; @@ -408,6 +411,7 @@ static Evas_Object *__add_widget_viewer_create_list(Evas_Object *content) LOGD("Genlist append %s", widget->app_id); widget_gl_item = elm_genlist_item_append(genlist, itc_widget, widget, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL); widget->genlist_item = widget_gl_item; + elm_atspi_accessible_can_highlight_set(widget_gl_item, EINA_FALSE); } evas_object_smart_callback_add(genlist, "realized", __add_widget_viewer_item_realized_cb, NULL); @@ -494,6 +498,51 @@ static Evas_Object *__add_widget_viewer_list_content_get_cb(void *data, Evas_Obj return main_box; } +static Eina_Bool __screen_reader_activate_cb(void *data, Evas_Object *obj, Elm_Access_Action_Info *action_info) +{ + Evas_Object *preview_layout = NULL; + + if (data == NULL || obj == NULL) { + LOGE("parameter is NULL"); + return EINA_FALSE; + } + + preview_layout = elm_atspi_accessible_parent_get(obj); + if (preview_layout == NULL) { + LOGE("Failed to get preview layout"); + return EINA_FALSE; + } + + __add_widget_viewer_preview_clicked_cb(data, preview_layout, NULL, NULL); + + return EINA_TRUE; +} + +static void __add_widget_viewer_create_screen_reader_obj(add_widget_data_t *widget, widget_size_type_e type, Evas_Object *preview_layout) +{ + int widget_w = 0, widget_h = 0; + char buf1[STR_MAX] = { 0, }; + char buf2[STR_MAX] = { 0, }; + Evas_Object *access_obj = NULL; + + if (widget == NULL || preview_layout == NULL) { + LOGE("parameter is NULL"); + return; + } + + access_obj = elm_access_object_register(preview_layout, preview_layout); + elm_atspi_accessible_name_set(access_obj, widget->label); + __add_widget_get_size_by_type(type, &widget_w, &widget_h); + snprintf(buf1, sizeof(buf1), _("IDS_HS_TBOPT_P1SD_BY_P2SD"), widget_w, widget_h); + snprintf(buf2, sizeof(buf2), "%s %s", buf1, _("IDS_HS_BODY_DOUBLE_TAP_TO_ADD_TTS")); + elm_atspi_accessible_description_set(access_obj, buf2); + elm_atspi_accessible_role_set(access_obj, ELM_ATSPI_ROLE_LIST_ITEM); + elm_atspi_accessible_translation_domain_set(access_obj, PACKAGE); + elm_atspi_accessible_reading_info_type_set(access_obj, (ELM_ACCESSIBLE_READING_INFO_TYPE_NAME | ELM_ACCESSIBLE_READING_INFO_TYPE_DESCRIPTION)); + elm_access_action_cb_set(access_obj, ELM_ACCESS_ACTION_ACTIVATE, __screen_reader_activate_cb, widget); + elm_atspi_accessible_can_highlight_set(access_obj, EINA_TRUE); +} + static Evas_Object *__add_widget_viewer_list_widget_box_create(Evas_Object *obj, add_widget_data_t *widget) { LOGD("Create box for %s", widget->widget_id); @@ -530,6 +579,7 @@ static Evas_Object *__add_widget_viewer_list_widget_box_create(Evas_Object *obj, case WIDGET_SIZE_TYPE_4x2: evas_object_size_hint_align_set(preview_layout, 0.0, 0.0); elm_box_pack_end(box, preview_layout); + __add_widget_viewer_create_screen_reader_obj(widget, preview->type, preview_layout); break; default: LOGE("Unsupported size\n"); @@ -632,6 +682,7 @@ static Evas_Object *__add_widget_viewer_list_widget_preview_box_create(Evas_Obje return preview_layout; } + static void __add_widget_viewer_preview_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source) { LOGD("Preview clicked"); @@ -660,3 +711,48 @@ static void __add_widget_viewer_preview_clicked_cb(void *data, Evas_Object *obj, cluster_data_insert_widget(widget_id, NULL, type); free(widget_id); } + +static void __add_widget_get_size_by_type(int type, int *w, int *h) +{ + switch (type) { + case WIDGET_SIZE_TYPE_1x1: + *w = 1; + *h = 1; + break; + case WIDGET_SIZE_TYPE_2x1: + *w = 2; + *h = 1; + break; + case WIDGET_SIZE_TYPE_2x2: + *w = 2; + *h = 2; + break; + case WIDGET_SIZE_TYPE_4x1: + *w = 4; + *h = 1; + break; + case WIDGET_SIZE_TYPE_4x2: + *w = 4; + *h = 2; + break; + case WIDGET_SIZE_TYPE_4x3: + *w = 4; + *h = 3; + break; + case WIDGET_SIZE_TYPE_4x4: + *w = 4; + *h = 4; + break; + case WIDGET_SIZE_TYPE_4x5: + *w = 4; + *h = 5; + break; + case WIDGET_SIZE_TYPE_4x6: + *w = 4; + *h = 6; + break; + default: + LOGE("type error : %d", type); + break; + } +} diff --git a/src/apps_view.c b/src/apps_view.c index aec592f..705fa0b 100755 --- a/src/apps_view.c +++ b/src/apps_view.c @@ -29,11 +29,15 @@ #include "menu.h" #include "mouse.h" #include "popup.h" +#include "screen_reader_handler.h" #define MAX_BADGE_COUNT_STR_LEN 5 #define MAX_BADGE_DISPLAY_COUNT 999 +#define MAP_BUF 0 + static struct { + Evas_Object *win; Evas_Object *scroller; Evas_Object *bg; Evas_Object *box; @@ -59,6 +63,7 @@ static struct { Ecore_Timer *edit_mode_scroll_timer; bool is_srolling; } apps_view_s = { + .win = NULL, .scroller = NULL, .bg = NULL, .box = NULL, @@ -111,7 +116,7 @@ static void __apps_view_create_base_gui(Evas_Object *win); static Evas_Object * __apps_view_add_page(void); static void __apps_view_remove_page(void); static void __apps_view_fill_apps(void *data, Ecore_Thread *th); -static void __apps_view_icon_clicked_cb(app_data_t *item); +static void __apps_view_icon_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source); static void __apps_view_icon_uninstall_btn_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source); static void __apps_view_delete_folder_cb(void *data, Evas_Object *obj, void *event_info); static void __apps_view_uninstall_app_cb(void *data, Evas_Object *obj, void *event_info); @@ -149,6 +154,7 @@ static void __apps_view_edit_drag_icon(void *data); static void __apps_view_edit_drop_icon(void *data); static Eina_Bool __apps_view_scroll_timer_cb(void *data); +static void __apps_view_scroll_drag_start_cb(void *data, Evas_Object *obj, void *event_info); static void __apps_view_scroll_anim_stop_cb(void *data, Evas_Object *obj, void *event_info); static void __apps_view_scroll_to_page(int page_idx, bool animation); static int __apps_view_get_index(int page_index, int x, int y); @@ -159,9 +165,17 @@ static void __apps_view_folder_entry_focused_cb(void *data, Evas_Object *obj, vo static void __apps_view_folder_entry_unfocused_cb(void *data, Evas_Object *obj, void *event_info); static void __apps_view_folder_entry_maxlength_reached_cb(void *data, Evas_Object *obj, void *event_info); +static void __apps_view_get_access_chooser_bar(Eina_List **list); +static void __apps_view_get_access_page_app_icon(Eina_List **list); +static void __apps_view_get_access_page_icon_delete_button(Eina_List **list); +static void __apps_view_get_access_folder(Eina_List **list); +static void __apps_view_get_access_folder_entry(Eina_List **list); +static void __apps_view_get_access_folder_icon(Eina_List **list); +static void __apps_view_get_access_folder_icon_delete_button(Eina_List **list); Evas_Object *apps_view_create(Evas_Object *win) { + apps_view_s.win = win; elm_win_screen_size_get(win, NULL, NULL, &apps_view_s.width, &apps_view_s.height); __apps_view_create_base_gui(win); @@ -481,7 +495,7 @@ bool apps_view_icon_set(app_data_t *item) int col, row; int x, y; int w, h; - char icon_container[STR_MAX]; + char icon_container[STR_MAX] = { 0, }; if (item == NULL) return false; @@ -504,7 +518,7 @@ bool apps_view_icon_set(app_data_t *item) grid = elm_object_part_content_get(page, APPS_VIEW_GRID); elm_grid_pack(grid, item->app_layout, x, y, w, h); - LOGD("[%s] -> [%s], [%p] page : %d", item->app_id, icon_container, item->app_layout, page_index); + LOGD("[%s : %s] -> [%s], [%p] page : %d", item->app_id, item->label_str, icon_container, item->app_layout, page_index); return true; } else if (apps_view_s.opened_folder && item->parent_db_id == apps_view_s.opened_folder->db_id) { row = (item->position / APPS_FOLDER_COL) % APPS_FOLDER_ROW; @@ -538,6 +552,22 @@ void apps_view_lang_changed(homescreen_view_t view_type) apps_data_update_item_label(); } +void apps_view_get_access_object_list(Eina_List **list) +{ + if (apps_view_s.opened_folder) { + __apps_view_get_access_folder(list); + return ; + } + __apps_view_get_access_chooser_bar(list); + __apps_view_get_access_page_app_icon(list); + __apps_view_get_access_page_icon_delete_button(list); + + if (apps_view_s.view_state == VIEW_STATE_NORMAL) { + homescreen_efl_get_access_menu_btn(list); + homescreen_efl_get_access_home_btn(list); + } +} + static void __apps_view_create_base_gui(Evas_Object *win) { char edj_path[PATH_MAX] = {0, }; @@ -587,6 +617,7 @@ static void __apps_view_create_base_gui(Evas_Object *win) evas_object_event_callback_add(apps_view_s.scroller, EVAS_CALLBACK_MOUSE_UP, __apps_view_scroller_up_cb, NULL); evas_object_smart_callback_add(apps_view_s.scroller, "scroll,anim,stop", __apps_view_scroll_anim_stop_cb, NULL); + evas_object_smart_callback_add(apps_view_s.scroller, "scroll,drag,start", __apps_view_scroll_drag_start_cb, NULL); apps_view_s.box = elm_box_add(apps_view_s.scroller); elm_box_horizontal_set(apps_view_s.box, EINA_TRUE); @@ -628,6 +659,7 @@ static Evas_Object *__apps_view_add_page(void) elm_object_part_content_set(page_ly, APPS_VIEW_GRID, grid); evas_object_show(page_ly); +#if MAP_BUF Evas_Object *mapbuf; mapbuf = elm_mapbuf_add(apps_view_s.box); @@ -640,6 +672,9 @@ static Evas_Object *__apps_view_add_page(void) evas_object_data_set(page_ly, "mapbuf", mapbuf); elm_mapbuf_enabled_set(mapbuf, EINA_TRUE); +#else + elm_box_pack_end(apps_view_s.box, page_ly); +#endif apps_view_s.page_list = eina_list_append(apps_view_s.page_list, page_ly); apps_view_s.page_count += 1; @@ -661,12 +696,18 @@ static void __apps_view_remove_page(void) apps_view_s.current_page = apps_view_s.page_count - 1; } +#if MAP_BUF Evas_Object *mapbuf = evas_object_data_get(item, "mapbuf"); elm_scroller_page_bring_in(apps_view_s.scroller, apps_view_s.current_page, 0); elm_box_unpack(apps_view_s.box, mapbuf); page_indicator_set_page_count(apps_view_s.indicator, apps_view_s.page_count); evas_object_del(mapbuf); +#else + elm_scroller_page_bring_in(apps_view_s.scroller, apps_view_s.current_page, 0); + elm_box_unpack(apps_view_s.box, item); + page_indicator_set_page_count(apps_view_s.indicator, apps_view_s.page_count); +#endif evas_object_del(item); } @@ -705,9 +746,10 @@ static void __apps_view_folder_fill_apps(void) apps_view_folder_reroder(); } -static void __apps_view_icon_clicked_cb(app_data_t *item) +static void __apps_view_icon_clicked_cb(void *data, Evas_Object *obj, const char *emission, const char *source) { app_control_h app_control_handle = NULL; + app_data_t *item = (app_data_t*) data; if (item->is_folder) { LOGD("%d(%s) folder clicked", item->db_id, item->label_str); @@ -770,10 +812,14 @@ static void __apps_view_icon_uninstall_btn_clicked_cb(void *data, Evas_Object *o popup_show(2, func, data, btn_text, title_text, popup_text); } else { apps_data_delete_folder(item); + + screen_reader_update(APPS); } } else if (item->type >= APPS_DATA_TYPE_APP_SHORTCUT) { LOGD("Delete shortcut"); apps_data_delete_item(item); + + screen_reader_update(APPS); } else { Evas_Smart_Cb func[3] = { __apps_view_uninstall_app_cb, NULL, NULL }; void *data[3] = { item, NULL, NULL }; @@ -793,6 +839,8 @@ static void __apps_view_delete_folder_cb(void *data, Evas_Object *obj, void *eve popup_hide(); app_data_t *item = (app_data_t *)data; apps_data_delete_folder(item); + + screen_reader_update(APPS); } static void __apps_view_uninstall_app_cb(void *data, Evas_Object *obj, void *event_info) @@ -970,6 +1018,12 @@ void apps_view_set_state(view_state_t state) if (item->is_removable && item != apps_view_s.picked_item) elm_object_signal_emit(item->app_layout, SIGNAL_UNINSTALL_BUTTON_SHOW_ANI, SIGNAL_SOURCE); elm_object_signal_emit(item->app_layout, SIGNAL_CHOOSER_MODE_OFF, SIGNAL_SOURCE); + + if (item->is_folder) { + screen_reader_update_description(item->app_layout, _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN")); + } else { + screen_reader_update_description(item->app_layout, _("IDS_HS_TBBODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_TO_FOLDER_TO_ADD_APP")); + } } } if (apps_view_s.dest_folder) @@ -1003,6 +1057,12 @@ void apps_view_set_state(view_state_t state) else if (item != apps_view_s.dest_folder) elm_object_signal_emit(item->app_layout, SIGNAL_CHOOSER_MODE_ON_FOLDER, SIGNAL_SOURCE); elm_object_signal_emit(item->app_layout, SIGNAL_UNINSTALL_BUTTON_HIDE_ANI, SIGNAL_SOURCE); + + if (item->is_folder) { + screen_reader_update_description(item->app_layout, _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN")); + } else { + screen_reader_update_description(item->app_layout, _("IDS_HS_TBBODY_DOUBLE_TAP_TO_SELECT")); + } } } @@ -1032,6 +1092,14 @@ void apps_view_set_state(view_state_t state) __apps_view__set_icon_label_style(item, VIEW_STATE_NORMAL); elm_object_signal_emit(item->app_layout, SIGNAL_UNINSTALL_BUTTON_HIDE_ANI, SIGNAL_SOURCE); elm_object_signal_emit(item->app_layout, SIGNAL_CHOOSER_MODE_OFF, SIGNAL_SOURCE); + + if (item->is_folder) { + char buf[STR_MAX] = { 0, }; + snprintf(buf, sizeof(buf), "%s %s", _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN"), _("IDS_BR_BODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_TO_REORDER_TTS")); + screen_reader_update_description(item->app_layout, buf); + } else { + screen_reader_update_description(item->app_layout, _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN")); + } } item->is_checked = false; } @@ -1045,6 +1113,8 @@ void apps_view_set_state(view_state_t state) apps_view_s.pre_view_state = apps_view_s.view_state; apps_view_s.view_state = state; + + screen_reader_update(APPS); } void apps_view_update_folder_icon(app_data_t* item) @@ -1164,6 +1234,8 @@ static void __apps_view_open_folder_popup(app_data_t *item) __apps_view_hide_folder_cb, NULL); evas_object_show(apps_view_s.folder_popup_ly); + + screen_reader_update(APPS); } static Eina_Bool __apps_view_show_folder_anim(void *data, double pos) @@ -1239,7 +1311,11 @@ static void __apps_view_close_folder_popup_done(void) apps_view_s.opened_folder = NULL; apps_view_s.animator = NULL; - __apps_view_scroll_to_page(page_idx, true); + if (page_idx == apps_view_s.current_page) { + screen_reader_update(APPS); + } else { + __apps_view_scroll_to_page(page_idx, true); + } } static void __apps_view_hide_folder_cb(void *data, Evas_Object *obj, const char *emission, const char *source) @@ -1302,11 +1378,8 @@ static void __apps_view_chooser_right_btn_clicked(void *data, Evas_Object *obj, static void __apps_view_update_chooser_text(int item_count) { char text1[STR_MAX], text2[STR_MAX]; - if (apps_view_s.selected_item_count + item_count > 0) { - snprintf(text1, sizeof(text1), _("IDS_MEMO_HEADER_PD_SELECTED_ABB2"), apps_view_s.selected_item_count + item_count); - } else - snprintf(text1, sizeof(text1), ""); + snprintf(text1, sizeof(text1), _("IDS_MEMO_HEADER_PD_SELECTED_ABB2"), apps_view_s.selected_item_count + item_count); snprintf(text2, sizeof(text2), APPS_VIEW_CHOOSER_TEXT, (int)APPS_VIEW_CHOOSER_TEXT_SIZE, text1); elm_object_part_text_set(apps_view_s.chooser_btn, APPS_CHOOSER_MIDDLE_LABEL, text2); @@ -1315,6 +1388,8 @@ static void __apps_view_update_chooser_text(int item_count) snprintf(text2, sizeof(text2), APPS_VIEW_CHOOSER_TEXT, (int)APPS_VIEW_CHOOSER_BUTTON_TEXT_SIZE, _("IDS_TPLATFORM_ACBUTTON_DONE_ABB")); elm_object_part_text_set(apps_view_s.chooser_btn, APPS_CHOOSER_RIGHT_LABEL, text2); + + screen_reader_update_name((Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(apps_view_s.chooser_btn), APPS_CHOOSER_MIDDLE_LABEL), text1); } static void __apps_view_badge_update_cb(unsigned int action, const char *app_id, unsigned int count, void *user_data) @@ -1567,7 +1642,7 @@ static void __apps_view_icon_up_cb(void *data, Evas *e, Evas_Object *obj, void * distance += (apps_mouse_info.move_y - apps_mouse_info.down_y) * (apps_mouse_info.move_y - apps_mouse_info.down_y); if (distance <= MOUSE_MOVE_MIN_DISTANCE) { - __apps_view_icon_clicked_cb((app_data_t *)data); + __apps_view_icon_clicked_cb(data, obj, NULL, NULL); } return ; } @@ -1635,6 +1710,9 @@ static void __apps_view_edit_pick_up_icon(void *data) int cx = -1, cy = -1; int gx = -1, gy = -1, gw = 0, gh = 0; Evas *e = NULL; + + screen_reader_update(CLEAR); + apps_view_s.picked_item = (app_data_t *)data; Evas_Object *icon_layout = apps_view_s.picked_item->app_layout; @@ -1649,6 +1727,7 @@ static void __apps_view_edit_pick_up_icon(void *data) apps_mouse_info.offset_x = cx - gx; apps_mouse_info.offset_y = cy - gy; +#if MAP_BUF Evas_Object *mapbuf = NULL; Evas_Object *page_ly = NULL; int page_index = apps_view_s.picked_item->position / (APPS_VIEW_COL*APPS_VIEW_ROW); @@ -1659,7 +1738,13 @@ static void __apps_view_edit_pick_up_icon(void *data) apps_view_icon_unset(apps_view_s.picked_item); elm_mapbuf_enabled_set(mapbuf, EINA_TRUE); +#else + Evas_Object *page_ly = NULL; + int page_index = apps_view_s.picked_item->position / (APPS_VIEW_COL*APPS_VIEW_ROW); + page_ly = eina_list_nth(apps_view_s.page_list, page_index); + apps_view_icon_unset(apps_view_s.picked_item); +#endif elm_object_signal_emit(icon_layout, SIGNAL_UNINSTALL_BUTTON_HIDE_ANI, SIGNAL_SOURCE); elm_object_signal_emit(icon_layout, SIGNAL_ICON_NAME_HIDE, SIGNAL_SOURCE); @@ -1768,6 +1853,8 @@ static void __apps_view_edit_drop_icon(void *data) } apps_data_sort(); apps_view_reorder(); + + screen_reader_update(APPS); } static Eina_Bool __apps_view_scroll_timer_cb(void *data) @@ -1784,12 +1871,23 @@ static Eina_Bool __apps_view_scroll_timer_cb(void *data) return ECORE_CALLBACK_RENEW; } +static void __apps_view_scroll_drag_start_cb(void *data, Evas_Object *obj, void *event_info) +{ + screen_reader_update(CLEAR); +} + static void __apps_view_scroll_anim_stop_cb(void *data, Evas_Object *obj, void *event_info) { apps_view_s.is_srolling = false; elm_scroller_current_page_get(obj, &apps_view_s.current_page, NULL); apps_view_s.current_page = apps_view_s.current_page % apps_view_s.page_count; LOGD("current page %d", apps_view_s.current_page); + + char *buf = (char *)malloc(sizeof(char)*1024); + snprintf(buf, 1024, _("IDS_HS_TBOPT_PAGE_P1SD_OF_P2SD"), apps_view_s.current_page + 1, apps_view_s.page_count); + screen_reader_read(buf); + screen_reader_update(APPS); + free(buf); } static void __apps_view_scroll_to_page(int page_idx, bool animation) @@ -1858,3 +1956,216 @@ static void __apps_view_folder_entry_maxlength_reached_cb(void *data, Evas_Objec { toast_unfocused_show(_("IDS_AT_TPOP_MAXIMUM_NUMBER_OF_CHARACTERS_REACHED")); } +static void __apps_view_get_access_chooser_bar(Eina_List **list) +{ + if (apps_view_s.view_state == VIEW_STATE_CHOOSER) { + access_info_t *title = (access_info_t *) malloc(sizeof(access_info_t)); + title->is_access_obj = EINA_FALSE; + title->target = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(apps_view_s.chooser_btn), APPS_CHOOSER_MIDDLE_LABEL); + title->parent = apps_view_s.chooser_btn; + title->name = strdup(edje_object_part_text_get(elm_layout_edje_get(apps_view_s.chooser_btn), APPS_CHOOSER_MIDDLE_LABEL)); + title->description = NULL; + title->role = ELM_ATSPI_ROLE_UNKNOWN; + title->clicked_cb = NULL; + title->cb_data = NULL; + title->priority = ACCESS_PRIORITY_CHOOSER_LABEL; + *list = eina_list_append(*list, title); + + access_info_t *cancel_btn = (access_info_t *) malloc(sizeof(access_info_t)); + cancel_btn->is_access_obj = EINA_FALSE; + cancel_btn->target = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(apps_view_s.chooser_btn), "chooser_left_clickable_space"); + cancel_btn->parent = apps_view_s.chooser_btn; + cancel_btn->name = strdup(_("IDS_TPLATFORM_ACBUTTON_CANCEL_ABB")); + cancel_btn->description = NULL; + cancel_btn->role = ELM_ATSPI_ROLE_UNKNOWN; + cancel_btn->clicked_cb = __apps_view_chooser_left_btn_clicked; + cancel_btn->cb_data = NULL; + cancel_btn->priority = ACCESS_PRIORITY_CHOOSER_CANCEL; + *list = eina_list_append(*list, cancel_btn); + + access_info_t *done_btn = (access_info_t *) malloc(sizeof(access_info_t)); + done_btn->is_access_obj = EINA_FALSE; + done_btn->target = (Evas_Object *) edje_object_part_object_get(elm_layout_edje_get(apps_view_s.chooser_btn), "chooser_right_clickable_space"); + done_btn->parent = apps_view_s.chooser_btn; + done_btn->name = strdup(_("IDS_TPLATFORM_ACBUTTON_DONE_ABB")); + done_btn->description = NULL; + done_btn->role = ELM_ATSPI_ROLE_UNKNOWN; + done_btn->clicked_cb = __apps_view_chooser_right_btn_clicked; + done_btn->cb_data = NULL; + done_btn->priority = ACCESS_PRIORITY_CHOOSER_DONE; + *list = eina_list_append(*list, done_btn); + } +} + +static void __apps_view_get_access_page_app_icon(Eina_List **list) +{ + Eina_List *find_list = NULL; + Eina_List *data_list = apps_data_get_list(); + app_data_t *item = NULL; + EINA_LIST_FOREACH(data_list, find_list, item) { + if (item->parent_db_id == APPS_ROOT) { + int page_index = item->position / (APPS_VIEW_COL*APPS_VIEW_ROW); + if (page_index == apps_view_s.current_page) { + char buf[STR_MAX] = { 0, }; + + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = item->app_layout; + info->parent = item->app_layout; + info->name = (item->label_str) ? strdup(item->label_str) : NULL; + if (item->is_folder) { + snprintf(buf, sizeof(buf), "%s %s", _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN"), _("IDS_BR_BODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_TO_REORDER_TTS")); + } else { + snprintf(buf, sizeof(buf), "%s", _("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN")); + } + info->description = strdup(buf); + info->role = ELM_ATSPI_ROLE_UNKNOWN; + if (apps_view_s.view_state == VIEW_STATE_CHOOSER) { + info->clicked_cb = __apps_view_icon_check_changed_cb; + } else{ + info->clicked_cb = __apps_view_icon_clicked_cb; + } + info->cb_data = item; + info->priority = (item->position + 1) * ACCESS_PRIORITY_APP_ICON; + + *list = eina_list_append(*list, info); + } + } + } +} + +static void __apps_view_get_access_page_icon_delete_button(Eina_List **list) +{ + if (apps_view_s.view_state == VIEW_STATE_EDIT) { + Eina_List *find_list = NULL; + Eina_List *data_list = apps_data_get_list(); + app_data_t *item = NULL; + + EINA_LIST_FOREACH(data_list, find_list, item) { + if (item->parent_db_id == APPS_ROOT && item->is_removable) { + int page_index = item->position / (APPS_VIEW_COL*APPS_VIEW_ROW); + if (page_index == apps_view_s.current_page) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(item->app_layout), APPS_ICON_UNINSTALL_BUTTON); + info->parent = item->app_layout; + info->name = (item->is_folder) ? strdup(_("IDS_HS_HEADER_REMOVE_FOLDER_ABB")) : strdup(_("IDS_AT_BODY_UNINSTALL")); + info->description = NULL; + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __apps_view_icon_uninstall_btn_clicked_cb; + info->cb_data = item; + info->priority = (item->position + 1) * ACCESS_PRIORITY_APP_ICON + ACCESS_PRIORITY_APP_ICON / 2; + + *list = eina_list_append(*list, info); + } + } + } + } +} + +static void __apps_view_get_access_folder(Eina_List **list) +{ + __apps_view_get_access_folder_entry(list); + __apps_view_get_access_folder_icon(list); + __apps_view_get_access_folder_icon_delete_button(list); +} + +static void __apps_view_get_access_folder_entry(Eina_List **list) +{ + const char *folder_text = NULL; + + if (!apps_view_s.opened_folder || !apps_view_s.folder_title_entry) + return ; + + + folder_text = elm_object_text_get(apps_view_s.folder_title_entry); + + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_TRUE; + info->target = apps_view_s.folder_title_entry; + info->parent = apps_view_s.opened_folder->folder_layout; + info->name = (folder_text) ? strdup(folder_text) : NULL; + info->description = strdup(_("IDS_ACCS_BODY_DOUBLE_TAP_TO_EDIT_T_TTS")); + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = NULL; + info->cb_data = NULL; + info->priority = ACCESS_PRIORITY_FOLDER_TITLE; + + *list = eina_list_append(*list, info); +} + +static void __apps_view_get_access_folder_icon(Eina_List **list) +{ + if (!apps_view_s.opened_folder) + return ; + + Eina_List *find_list = NULL; + Eina_List *data_list = apps_data_get_list(); + app_data_t *item = NULL; + int item_count = 0; + EINA_LIST_FOREACH(data_list, find_list, item) { + if (item->parent_db_id == apps_view_s.opened_folder->db_id) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = item->app_layout; + info->parent = apps_view_s.opened_folder->folder_layout; + info->name = (item->label_str) ? strdup(item->label_str) : NULL; + info->description = (apps_view_s.view_state == VIEW_STATE_EDIT) ? strdup(_("IDS_HS_TBBODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_OUTSIDE_TO_REMOVE_FROM_FOLDER")) : strdup(_("IDS_LCKSCN_TBBODY_DOUBLE_TAP_TO_OPEN")); + info->role = ELM_ATSPI_ROLE_UNKNOWN; + if (apps_view_s.view_state == VIEW_STATE_CHOOSER) + info->clicked_cb = __apps_view_icon_check_changed_cb; + else + info->clicked_cb = __apps_view_icon_clicked_cb; + info->cb_data = item; + info->priority = (item->position + 1) * ACCESS_PRIORITY_APP_ICON; + + *list = eina_list_append(*list, info); + item_count += 1; + } + } + + if (item_count < APPS_FOLDER_MAX_ITEM) { + int pos = item_count; + if (apps_view_s.view_state != VIEW_STATE_CHOOSER) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(apps_view_s.folder_popup_ly), APPS_FOLDER_PLUS_ICON); + info->parent = apps_view_s.win; + info->name = strdup(_("IDS_HS_TBOPT_ADD_APPS_TO_FOLDER")); + info->description = NULL; + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __apps_view_plus_icon_clicked; + info->cb_data = apps_view_s.opened_folder; + info->priority = (pos + 1) * ACCESS_PRIORITY_APP_ICON; + + *list = eina_list_append(*list, info); + } + } +} + +static void __apps_view_get_access_folder_icon_delete_button(Eina_List **list) +{ + if (!apps_view_s.opened_folder) + return ; + + Eina_List *find_list = NULL; + Eina_List *data_list = apps_data_get_list(); + app_data_t *item = NULL; + EINA_LIST_FOREACH(data_list, find_list, item) { + if (item->parent_db_id == apps_view_s.opened_folder->db_id) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(item->app_layout), APPS_ICON_UNINSTALL_BUTTON); + info->parent = item->app_layout; + info->name = strdup(_("IDS_AT_BODY_UNINSTALL")); + info->description = NULL; + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __apps_view_icon_uninstall_btn_clicked_cb; + info->cb_data = item; + info->priority = (item->position + 1) * ACCESS_PRIORITY_APP_ICON + ACCESS_PRIORITY_APP_ICON / 2; + + *list = eina_list_append(*list, info); + } + } +} + diff --git a/src/cluster_page.c b/src/cluster_page.c index 09ab3cf..4c2c963 100755 --- a/src/cluster_page.c +++ b/src/cluster_page.c @@ -20,6 +20,7 @@ #include "util.h" #include "widget_viewer.h" #include "cluster_view.h" +#include "screen_reader_handler.h" #define FLOAT_TIME 0.15 @@ -196,6 +197,32 @@ void cluster_page_get_highlight_xy(cluster_page_t *page, int *x, int *y) } } +void cluster_page_get_access_widget_list(cluster_page_t *page_t, Eina_List **list, Eina_Bool is_edit) +{ + Eina_List *find_list; + widget_data_t *item; + + EINA_LIST_FOREACH(page_t->widget_list, find_list, item) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = item->widget_layout; + info->parent = page_t->page_layout; + info->name = strdup(item->pkg_name); + info->description = strdup(_("IDS_BR_BODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_TO_REORDER_TTS")); + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = NULL; + info->cb_data = NULL; + info->priority = (item->pos_y * CLUSTER_COL + item->pos_x) * ACCESS_PRIORITY_WIDGET; + + *list = eina_list_append(*list, info); + + if (is_edit) { + access_info_t *btn_info = widget_viewer_get_accessible_delete_btn(item); + *list = eina_list_append(*list, btn_info); + } + } +} + Evas_Object *cluster_page_thumbnail(cluster_page_t *page_t) { Evas_Object *image = NULL; diff --git a/src/cluster_view.c b/src/cluster_view.c index 39c607d..40c80ec 100755 --- a/src/cluster_view.c +++ b/src/cluster_view.c @@ -29,6 +29,7 @@ #include "cluster_data.h" #include "add_widget_viewer/add_widget_viewer.h" #include "mouse.h" +#include "screen_reader_handler.h" static struct { Evas_Object *win; @@ -129,6 +130,7 @@ static Eina_Bool __cluster_view_thumbnail_long_press_time_cb(void *data); static void __cluster_view_allpage_drag_page(void *data); static void __cluster_view_allpage_pick_up_page(void *data); static void __cluster_view_allpage_drop_page(void *data); +static void __cluster_view_allpage_clicked_page(void *data, Evas_Object *obj, const char *emission, const char *source); static void __clsuter_view_widget_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); static void __clsuter_view_widget_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info); @@ -150,6 +152,10 @@ static int __cluster_view_allpage_get_page_index(int x, int y); static void __cluster_view_allpage_reposition(void); static int __cluster_view_page_sort_cb(const void *a , const void *b); +static void __cluster_view_get_access_page_thumbnail(Eina_List **list); +static void __cluster_view_get_access_page_delete_button(Eina_List **list); +static void __cluster_view_get_access_add_page(Eina_List **list); + Evas_Object *cluster_view_create(Evas_Object *win) { cluster_view_s.win = win; @@ -510,6 +516,7 @@ bool cluster_view_set_state(view_state_t state) } cluster_view_s.view_state = state; + screen_reader_update(HOME); return true; } @@ -603,6 +610,8 @@ void cluster_view_delete_widget(widget_data_t *item) evas_object_del(item->widget_layout); item->widget_layout = NULL; } + + screen_reader_update(HOME); } void cluster_view_edit_on_done(cluster_page_t *page) @@ -616,6 +625,91 @@ void cluster_view_edit_on_done(cluster_page_t *page) } } +void cluster_view_get_access_object_list(Eina_List **list) +{ + if (cluster_view_s.view_state == VIEW_STATE_NORMAL) { + cluster_page_t *page = (cluster_page_t *)eina_list_nth(cluster_view_s.page_list, cluster_view_s.current_page); + cluster_page_get_access_widget_list(page, list, EINA_FALSE); + + homescreen_efl_get_access_menu_btn(list); + homescreen_efl_get_access_apps_btn(list); + } else if (cluster_view_s.view_state == VIEW_STATE_EDIT) { + cluster_page_t *page = (cluster_page_t *)eina_list_nth(cluster_view_s.page_list, cluster_view_s.current_page); + cluster_page_get_access_widget_list(page, list, EINA_TRUE); + } else if (cluster_view_s.view_state == VIEW_STATE_ALL_PAGE) { + __cluster_view_get_access_page_thumbnail(list); + __cluster_view_get_access_page_delete_button(list); + + __cluster_view_get_access_add_page(list); + } +} + +static void __cluster_view_get_access_page_thumbnail(Eina_List **list) +{ + Eina_List *find_list = NULL; + cluster_page_t *page_item = NULL; + EINA_LIST_FOREACH(cluster_view_s.page_list, find_list, page_item) { + if (page_item->thumbnail_ly) { + char buf[STR_MAX] = { 0, }; + snprintf(buf, sizeof(buf), _("IDS_HS_TBOPT_PAGE_P1SD_OF_P2SD"), page_item->page_index + 1, cluster_view_s.page_count); + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = page_item->thumbnail_ly; + info->parent = page_item->page_layout; + info->name = strdup(buf); + info->description = strdup(_("IDS_BR_BODY_DOUBLE_TAP_AND_HOLD_THEN_DRAG_TO_REORDER_TTS")); + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __cluster_view_allpage_clicked_page; + info->cb_data = page_item; + info->priority = (page_item->page_index + 1) * ACCESS_PRIORITY_ALL_PAGE; + + *list = eina_list_append(*list, info); + } + } +} + +static void __cluster_view_get_access_page_delete_button(Eina_List **list) +{ + if (eina_list_count(cluster_view_s.page_list) > 1) { + Eina_List *find_list = NULL; + cluster_page_t *page_item = NULL; + EINA_LIST_FOREACH(cluster_view_s.page_list, find_list, page_item) { + if (page_item->thumbnail_ly) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(page_item->thumbnail_ly), CLUSTER_ALLPAGE_DELETE_BUTTON); + info->parent = page_item->thumbnail_ly; + info->name = strdup(_("IDS_HS_HEADER_DELETE_PAGE_ABB2")); + info->description = NULL; + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __cluster_view_allpage_delete_clicked; + info->cb_data = page_item; + info->priority = (page_item->page_index + 1) * ACCESS_PRIORITY_ALL_PAGE + ACCESS_PRIORITY_ALL_PAGE / 2; + + *list = eina_list_append(*list, info); + } + } + } +} + +static void __cluster_view_get_access_add_page(Eina_List **list) +{ + if (cluster_view_s.allpage_add_page) { + access_info_t *info = (access_info_t *)malloc(sizeof(access_info_t)); + info->is_access_obj = EINA_FALSE; + info->target = cluster_view_s.allpage_add_page; + info->parent = cluster_view_s.allpage_grid; + info->name = strdup(_("IDS_HS_BODY_CREATE_PAGE")); + info->description = NULL; + info->role = ELM_ATSPI_ROLE_UNKNOWN; + info->clicked_cb = __cluster_view_allpage_add_clicked; + info->cb_data = NULL; + info->priority = (CLUSTER_MAX_PAGE + 1) * ACCESS_PRIORITY_ALL_PAGE; + + *list = eina_list_append(*list, info); + } +} + static void __cluster_view_scroll_to_home(void) { __cluster_view_scroll_to_page(CLUSTER_HOME_PAGE, true); @@ -919,6 +1013,8 @@ static void __cluster_view_allpage_add_clicked(void *data, Evas_Object *obj, con evas_object_del(cluster_view_s.allpage_add_page); cluster_view_s.allpage_add_page = NULL; } + + screen_reader_update(HOME); } static void __cluster_view_allpage_delete_page_cb(void *data, Evas_Object *obj, void *event_info) @@ -969,6 +1065,7 @@ static void __cluster_view_allpage_delete_page_cb(void *data, Evas_Object *obj, elm_grid_pack(cluster_view_s.allpage_grid, cluster_view_s.allpage_add_page, x, y, CLUSTER_ALL_PAGE_W, CLUSTER_ALL_PAGE_H); } popup_hide(); + screen_reader_update(HOME); } static void __clsuter_view_thumbnail_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) @@ -993,7 +1090,7 @@ static void __clsuter_view_thumbnail_down_cb(void *data, Evas *e, Evas_Object * static void __clsuter_view_thumbnail_up_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) { - cluster_page_t *page_t = (cluster_page_t *)data; + cluster_page_t *page_t = (cluster_page_t *) data; Evas_Event_Mouse_Up* ev = event_info; LOGD("UP: (%d,%d)", ev->output.x, ev->output.y); @@ -1084,6 +1181,14 @@ static Eina_Bool __cluster_view_thumbnail_long_press_time_cb(void *data) return ECORE_CALLBACK_CANCEL; } +static void __cluster_view_allpage_clicked_page(void *data, Evas_Object *obj, const char *emission, const char *source) +{ + cluster_page_t *page_t = (cluster_page_t *)data; + + cluster_view_s.current_page = page_t->page_index; + cluster_view_set_state(VIEW_STATE_NORMAL); +} + static void __cluster_view_allpage_drag_page(void *data) { if (cluster_view_s.picked_page) { @@ -1130,6 +1235,8 @@ static void __cluster_view_allpage_drag_page(void *data) static void __cluster_view_allpage_pick_up_page(void *data) { + screen_reader_update(CLEAR); + cluster_view_s.picked_page = (cluster_page_t *)data; elm_grid_unpack(cluster_view_s.allpage_grid, cluster_view_s.picked_page->thumbnail_ly); @@ -1166,6 +1273,8 @@ static void __cluster_view_allpage_drop_page(void *data) cluster_data_update(widget_item); } } + + screen_reader_update(HOME); } static void __clsuter_view_widget_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) @@ -1275,6 +1384,9 @@ static void __cluster_view_edit_pick_up_widget(void *data) int cx = -1, cy = -1; int gx = -1, gy = -1, gw = 0, gh = 0; Evas *e = NULL; + + screen_reader_update(CLEAR); + cluster_view_s.picked_widget = (widget_data_t *)data; Evas_Object *widget_layout = cluster_view_s.picked_widget->widget_layout; @@ -1385,6 +1497,7 @@ static void __cluster_view_edit_drop_widget(void *data) evas_object_event_callback_del(cluster_view_s.picked_widget->widget_content, EVAS_CALLBACK_MOUSE_MOVE, __clsuter_view_widget_move_cb); evas_object_event_callback_del(cluster_view_s.picked_widget->widget_content, EVAS_CALLBACK_MOUSE_UP, __clsuter_view_widget_up_cb); } + static Eina_Bool __cluster_view_edit_move_anim(void *data, double pos) { evas_object_move(cluster_view_s.picked_widget->widget_layout, @@ -1422,6 +1535,7 @@ static void __cluster_view_edit_move_anim_done(void *data) } cluster_view_s.picked_widget = NULL; + screen_reader_update(HOME); } static void __clsuter_view_scroller_down_cb(void *data, Evas *e, Evas_Object *obj, void *event_info) @@ -1513,6 +1627,8 @@ static Eina_Bool __cluster_view_scroller_long_press_time_cb(void *data) } static void __cluster_view_scroll_drag_start_cb(void *data, Evas_Object *obj, void *event_info) { + screen_reader_update(CLEAR); + cluster_view_s.is_srolling = true; cluster_page_t *current_page = (cluster_page_t *)eina_list_nth(cluster_view_s.page_list, cluster_view_s.current_page); Eina_List *find_list = NULL; @@ -1525,10 +1641,16 @@ static void __cluster_view_scroll_drag_start_cb(void *data, Evas_Object *obj, vo static void __cluster_view_scroll_anim_stop_cb(void *data, Evas_Object *obj, void *event_info) { + char buf[STR_MAX] = { 0 , }; + cluster_view_s.is_srolling = false; elm_scroller_current_page_get(obj, &cluster_view_s.current_page, NULL); cluster_view_s.current_page = cluster_view_s.current_page % cluster_view_s.page_count; LOGD("current page %d", cluster_view_s.current_page); + + snprintf(buf, sizeof(buf), _("IDS_HS_TBOPT_PAGE_P1SD_OF_P2SD"), cluster_view_s.current_page + 1, cluster_view_s.page_count); + screen_reader_read(buf); + screen_reader_update(HOME); } static Eina_Bool __cluster_view_scroll_timer_cb(void *data) diff --git a/src/homescreen-efl.c b/src/homescreen-efl.c index c788784..00737d0 100755 --- a/src/homescreen-efl.c +++ b/src/homescreen-efl.c @@ -29,6 +29,7 @@ #include "menu.h" #include "popup.h" #include "add_widget_viewer/add_widget_viewer.h" +#include "screen_reader_handler.h" static struct { Evas_Object *win; @@ -378,6 +379,7 @@ static void __homescreen_efl_change_view(void) elm_object_signal_emit(main_info.btn_layout, SIGNAL_HOME_BTN_ICON_HIDE, SIGNAL_SOURCE); elm_object_signal_emit(main_info.btn_layout, SIGNAL_APPS_BTN_ICON_SHOW, SIGNAL_SOURCE); main_info.view_type = HOMESCREEN_VIEW_HOME; + screen_reader_update(HOME); } else if (main_info.view_type == HOMESCREEN_VIEW_HOME) { cluster_view_hide(); main_info.animator = ecore_animator_timeline_add(HOME_ANIMATION_TIME, __homescreen_efl_show_apps_anim, NULL); @@ -385,6 +387,7 @@ static void __homescreen_efl_change_view(void) elm_object_signal_emit(main_info.btn_layout, SIGNAL_APPS_BTN_ICON_HIDE, SIGNAL_SOURCE); elm_object_signal_emit(main_info.btn_layout, SIGNAL_HOME_BTN_ICON_SHOW, SIGNAL_SOURCE); main_info.view_type = HOMESCREEN_VIEW_APPS; + screen_reader_update(APPS); } } @@ -509,11 +512,72 @@ static bool __homescreen_efl_create_view(void) return true; } - static Eina_Bool __homescreen_efl_init_view(void *data) { cluster_view_init(); apps_view_init(); + screen_reader_update(HOME); + return ECORE_CALLBACK_CANCEL; } + +void homescreen_efl_get_access_menu_btn(Eina_List **list) +{ + Evas_Object *menu_btn = NULL; + access_info_t *btn_info = NULL; + + menu_btn = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(main_info.btn_layout), MENU_BUTTON); + btn_info = (access_info_t *)malloc(sizeof(access_info_t)); + btn_info->is_access_obj = EINA_FALSE; + btn_info->target = menu_btn; + btn_info->parent = main_info.btn_layout; + btn_info->name = strdup(_("IDS_HS_BODY_MENU")); + btn_info->description = strdup(_("IDS_ST_BODY_DOUBLE_TAP_TO_OPEN_THE_MENU_T_TTS")); + btn_info->role = ELM_ATSPI_ROLE_UNKNOWN; + btn_info->clicked_cb = __homescreen_efl_menu_btn_clicked; + btn_info->cb_data = NULL; + btn_info->priority = ACCESS_PRIORITY_MENUBUTTON; + + *list = eina_list_append(*list, btn_info); +} + +void homescreen_efl_get_access_apps_btn(Eina_List **list) +{ + Evas_Object *apps_btn = NULL; + access_info_t *btn_info = NULL; + + apps_btn = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(main_info.btn_layout), HOME_BUTTON); + btn_info = (access_info_t *)malloc(sizeof(access_info_t)); + btn_info->is_access_obj = EINA_FALSE; + btn_info->target = apps_btn; + btn_info->parent = main_info.btn_layout; + btn_info->name = strdup(_("IDS_AT_TAB4_ALL_APPS")); + btn_info->description = strdup(_("IDS_HS_TBBODY_DOUBLE_TAP_TO_GO_TO_APPS_SCREEN")); + btn_info->role = ELM_ATSPI_ROLE_UNKNOWN; + btn_info->clicked_cb = __homescreen_efl_home_btn_clicked; + btn_info->cb_data = NULL; + btn_info->priority = ACCESS_PRIORITY_APPSBUTTON; + + *list = eina_list_append(*list, btn_info); +} + +void homescreen_efl_get_access_home_btn(Eina_List **list) +{ + Evas_Object *home_btn = NULL; + access_info_t *btn_info = NULL; + + home_btn = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(main_info.btn_layout), HOME_BUTTON); + btn_info = (access_info_t *)malloc(sizeof(access_info_t)); + btn_info->is_access_obj = EINA_FALSE; + btn_info->target = home_btn; + btn_info->parent = main_info.btn_layout; + btn_info->name = strdup(_("IDS_HS_TBOPT_HOME_M_HOMESCREEN")); + btn_info->description = strdup(_("IDS_HS_TBBODY_DOUBLE_TAP_TO_GO_TO_HOME_SCREEN")); + btn_info->role = ELM_ATSPI_ROLE_UNKNOWN; + btn_info->clicked_cb = __homescreen_efl_home_btn_clicked; + btn_info->cb_data = NULL; + btn_info->priority = ACCESS_PRIORITY_HOMEBUTTON; + + *list = eina_list_append(*list, btn_info); +} diff --git a/src/screen_reader_handler.c b/src/screen_reader_handler.c new file mode 100755 index 0000000..a1e6fc3 --- /dev/null +++ b/src/screen_reader_handler.c @@ -0,0 +1,198 @@ +/* + * Copyright 2012 Samsung Electronics Co., Ltd + * + * Licensed under the Flora License, Version 1.1 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://floralicense.org/license/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util.h" +#include "screen_reader_handler.h" +#include "cluster_view.h" +#include "apps_view.h" +#include "homescreen-efl.h" + +static struct { + screen_reader_t current_type; + Eina_List *access_list; +} screen_reader_s = { + .current_type = INIT_TYPE, + .access_list = NULL, +}; + +static void __screen_reader_deregister(void); +static void __screen_reader_update_home(void); +static void __screen_reader_update_apps(void); +static Eina_Bool __screen_reader_register_object(void *data); +static Eina_Bool __screen_reader_activate_cb(void *data, Evas_Object *obj, Elm_Access_Action_Info *action_info); +static int __screen_reader_accessible_object_sort_cb(const void *a , const void *b); +static void __screen_reader_say_cb(void *data, const char *signal); + +void screen_reader_update(screen_reader_t type) +{ + screen_reader_s.current_type = type; + + __screen_reader_deregister(); + + switch (type) { + case HOME: __screen_reader_update_home(); break; + case APPS: __screen_reader_update_apps(); break; + default: break; + } +} + +void screen_reader_update_name(Evas_Object *target_obj, const char *name) +{ + Eina_List *find_list = NULL; + access_info_t *item = NULL; + + if (target_obj == NULL) { + LOGE("target object is NULL"); + return; + } + + EINA_LIST_FOREACH(screen_reader_s.access_list, find_list, item) { + if (item->target != target_obj) continue; + + if (name) { + Evas_Object *access_obj = NULL; + + free(item->name); + + item->name = strdup(name); + + access_obj = elm_access_object_get(item->target); + if (access_obj) { + elm_atspi_accessible_name_set(access_obj, item->name); + } + } + } +} + +void screen_reader_update_description(Evas_Object *target_obj, const char *description) +{ + Eina_List *find_list = NULL; + access_info_t *item = NULL; + + if (target_obj == NULL) { + LOGE("target object is NULL"); + return; + } + + EINA_LIST_FOREACH(screen_reader_s.access_list, find_list, item) { + if (item->target != target_obj) continue; + + if (description) { + Evas_Object *access_obj = NULL; + + free(item->description); + + item->description = strdup(description); + + access_obj = elm_access_object_get(item->target); + if (access_obj) { + elm_atspi_accessible_description_set(access_obj, item->description); + } + } + } +} + +void screen_reader_read(char *str) +{ + elm_atspi_bridge_utils_say(str, EINA_TRUE, __screen_reader_say_cb, NULL); +} + +void __screen_reader_deregister(void) +{ + Eina_List *find_list = NULL; + access_info_t *item = NULL; + + EINA_LIST_FOREACH(screen_reader_s.access_list, find_list, item) { + Evas_Object *access_obj = elm_access_object_get(item->target); + elm_access_object_unregister(item->target); + evas_object_del(access_obj); + free(item->name); + free(item->description); + free(item); + } + + screen_reader_s.access_list = eina_list_free(screen_reader_s.access_list); +} + +void __screen_reader_update_home(void) +{ + cluster_view_get_access_object_list(&screen_reader_s.access_list); + + ecore_timer_add(0.1, __screen_reader_register_object, NULL); +} + +static void __screen_reader_update_apps(void) +{ + apps_view_get_access_object_list(&screen_reader_s.access_list); + + ecore_timer_add(0.3, __screen_reader_register_object, NULL); +} + +static Eina_Bool __screen_reader_register_object(void *data) +{ + Eina_List *find_list = NULL; + access_info_t *item = NULL; + Evas_Object *prev_obj = NULL; + + screen_reader_s.access_list = eina_list_sort(screen_reader_s.access_list, + eina_list_count(screen_reader_s.access_list), __screen_reader_accessible_object_sort_cb); + + EINA_LIST_FOREACH(screen_reader_s.access_list, find_list, item) { + Evas_Object *access_obj = NULL; + if (item->is_access_obj) { + access_obj = item->target; + } else { + access_obj = elm_access_object_register(item->target, item->parent); + elm_atspi_accessible_name_set(access_obj, item->name); + elm_atspi_accessible_description_set(access_obj, item->description); + elm_atspi_accessible_translation_domain_set(access_obj, PACKAGE); + elm_atspi_accessible_reading_info_type_set(access_obj, (ELM_ACCESSIBLE_READING_INFO_TYPE_NAME | + ELM_ACCESSIBLE_READING_INFO_TYPE_DESCRIPTION)); + elm_access_action_cb_set(access_obj, ELM_ACCESS_ACTION_ACTIVATE, __screen_reader_activate_cb, item); + } + if (prev_obj) { + elm_atspi_accessible_relationship_append(prev_obj, ELM_ATSPI_RELATION_FLOWS_TO, access_obj); + elm_atspi_accessible_relationship_append(access_obj, ELM_ATSPI_RELATION_FLOWS_FROM, prev_obj); + } + prev_obj = access_obj; + } + + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool __screen_reader_activate_cb(void *data, Evas_Object *obj, Elm_Access_Action_Info *action_info) +{ + access_info_t *info = (access_info_t*)data; + + if (info && info->clicked_cb) { + (*info->clicked_cb)(info->cb_data, info->target, NULL, NULL); + } + + return EINA_TRUE; +} + +static int __screen_reader_accessible_object_sort_cb(const void *a , const void *b) +{ + access_info_t *item1 = (access_info_t *)a; + access_info_t *item2 = (access_info_t *)b; + + return item1->priority - item2->priority; +} + +static void __screen_reader_say_cb(void *data, const char *signal) +{ + +} diff --git a/src/widget_viewer.c b/src/widget_viewer.c index 915c4c9..f964e9d 100755 --- a/src/widget_viewer.c +++ b/src/widget_viewer.c @@ -246,3 +246,19 @@ void widget_viewer_resume_widget(widget_data_t *widget_data) LOGE("Failed to resume widget(%d)", ret); } } + +access_info_t *widget_viewer_get_accessible_delete_btn(widget_data_t *widget_data) +{ + access_info_t *btn_info = (access_info_t *)malloc(sizeof(access_info_t)); + btn_info->is_access_obj = EINA_FALSE; + btn_info->target = (Evas_Object *)edje_object_part_object_get(elm_layout_edje_get(widget_data->widget_layout), WIDGET_DELETE_BUTTON); + btn_info->parent = widget_data->widget_layout; + btn_info->name = strdup(_("IDS_HS_OPT_DELETE")); + btn_info->description = NULL; + btn_info->role = ELM_ATSPI_ROLE_UNKNOWN; + btn_info->clicked_cb = __widget_viewer_delete_btn_clicked_cb; + btn_info->cb_data = widget_data; + btn_info->priority = (widget_data->pos_y * CLUSTER_COL + widget_data->pos_x) * ACCESS_PRIORITY_WIDGET + (ACCESS_PRIORITY_WIDGET / 2); + + return btn_info; +} -- 2.7.4