TizenRefApp-9083 [Call UI] Implement Screen Reader highlight logic for KeypadPage 22/143322/5
authorIgor Olshevskyi <i.olshevskyi@samsung.com>
Wed, 9 Aug 2017 09:01:34 +0000 (12:01 +0300)
committerIgor Olshevskyi <i.olshevskyi@samsung.com>
Fri, 11 Aug 2017 14:14:01 +0000 (17:14 +0300)
Change-Id: Ib8143cab96a0111dfd6f9b96bf282b22df9fb1e0

inc/presenters/KeypadPage.h
project_def.prop
src/presenters/AccessoryPresenter.cpp
src/presenters/KeypadPage.cpp
src/view/common.h

index 027ce6453535e6363f12d6dc1ce6c11adad01e95..2ca6a1b0ae616c33eb0c94f567fba6fbd9cd2bb9 100644 (file)
@@ -79,6 +79,19 @@ namespace callui {
                void registerCallbacks();
                void unregisterCallbacks();
 
+               // Screen Reader
+               ucl::Result createAtspiHighlightHelper();
+               Elm_Interface_Atspi_Accessible *onAtspiHighlight(
+                               Elm_Interface_Atspi_Accessible *ao,
+                               Elm_Atspi_Relation_Type flowRelation);
+               ucl::ElmWidget *getFirstButton();
+               ucl::ElmWidget *getLastButton();
+               void registerVolumeControlAo();
+               void onVolumeControlScreenReaderReadStart(
+                               ucl::Widget &widget,
+                               void *eventInfo);
+
+
                // Page
 
                virtual void onBackKey() override final;
@@ -94,6 +107,9 @@ namespace callui {
                Ecore_Timer *m_vcTimer;
 
                AudioStateType m_audioState;
+
+               // Screen Reader
+               AtspiHighlightHelperSRef m_atspiHelper;
        };
 }
 
index 1fe3c17366ba49fd1dae6ba6f9e5f176596f7d87..7bc0ea9444e57924b48008ca1f6f92a2a6765673 100644 (file)
@@ -9,7 +9,7 @@ type = app
 profile = wearable-4.0
 
 # C/CPP Sources
-USER_SRCS = ucl/src/gui/WidgetItem.cpp src/presenters/InstanceManager.cpp ucl/src/appfw/UIApp.cpp src/model/VoiceControlStateProvider.cpp src/presenters/AcceptDialog.cpp ucl/src/gui/NaviItem.cpp ucl/src/gui/Layout.cpp src/model/IncomingCall.cpp src/presenters/Page.cpp src/resources.cpp src/presenters/DeviceStatePresenter.cpp src/model/ContactInfoProvider.cpp ucl/src/gui/Genlist.cpp ucl/src/gui/Window.cpp src/types.cpp src/presenters/RejectMsgPresenter.cpp src/model/ConnectionStateSource.cpp src/presenters/AccessoryPresenter.cpp src/model/ContactInfo.cpp src/model/EndCall.cpp src/presenters/MainPage.cpp src/view/helpers.cpp ucl/src/mvp/ListItemPresenter.cpp ucl/src/util/types/Result.cpp ucl/src/mvp/ListPresenter.cpp ucl/src/misc/Variant.cpp src/model/CallUI.cpp ucl/src/mvp/GuiPresenter.cpp src/view/VolumeControl.cpp src/view/Slider.cpp src/model/CallInfo.cpp ucl/src/gui/ElmWidget.cpp src/model/SimSlotStateSource.cpp src/presenters/AcceptRejectPresenter.cpp ucl/src/gui/EdjeWidget.cpp ucl/src/gui/Naviframe.cpp src/model/CallManager.cpp ucl/src/misc/Timeout.cpp src/presenters/Instance.cpp ucl/src/gui/Widget.cpp src/model/ActiveCall.cpp src/model/RejectMsgProvider.cpp src/presenters/MoreOptionsPresenter.cpp ucl/src/appfw/SysEventProvider.cpp src/presenters/CallInfoPresenter.cpp src/model/BatteryStateSource.cpp src/model/CallClient.cpp src/model/VoiceControlStateSource.cpp src/model/RssiStateSource.cpp src/model/HdVoiceStateSource.cpp ucl/src/util/logging.cpp src/model/IndicatorStateProvider.cpp src/presenters/KeypadPage.cpp src/presenters/helpers.cpp src/presenters/MotionSensorPresenter.cpp src/main.cpp src/model/MsgClient.cpp src/presenters/IndicatorPresenter.cpp ucl/src/appfw/helpers.cpp src/model/CallUIBuilder.cpp src/presenters/CallStatusPresenter.cpp src/model/ConferenceCallInfo.cpp src/model/HeldCall.cpp src/model/SoundManager.cpp src/model/BluetoothManager.cpp src/model/RejectMsg.cpp src/view/AcceptRejectWidget.cpp ucl/src/appfw/InstanceManagerBase.cpp 
+USER_SRCS = ucl/src/gui/WidgetItem.cpp src/presenters/InstanceManager.cpp ucl/src/appfw/UIApp.cpp src/model/VoiceControlStateProvider.cpp src/presenters/AcceptDialog.cpp ucl/src/gui/NaviItem.cpp ucl/src/gui/Layout.cpp src/model/IncomingCall.cpp src/presenters/Page.cpp src/resources.cpp src/presenters/DeviceStatePresenter.cpp src/model/ContactInfoProvider.cpp ucl/src/gui/Genlist.cpp ucl/src/gui/Window.cpp src/types.cpp src/presenters/RejectMsgPresenter.cpp src/model/ConnectionStateSource.cpp src/presenters/AccessoryPresenter.cpp src/model/ContactInfo.cpp src/model/EndCall.cpp src/presenters/MainPage.cpp src/view/helpers.cpp ucl/src/mvp/ListItemPresenter.cpp ucl/src/util/types/Result.cpp ucl/src/mvp/ListPresenter.cpp ucl/src/misc/Variant.cpp src/model/CallUI.cpp ucl/src/mvp/GuiPresenter.cpp src/view/VolumeControl.cpp src/view/Slider.cpp src/model/CallInfo.cpp ucl/src/gui/ElmWidget.cpp src/model/SimSlotStateSource.cpp src/presenters/AcceptRejectPresenter.cpp ucl/src/gui/EdjeWidget.cpp ucl/src/gui/Naviframe.cpp src/model/CallManager.cpp ucl/src/misc/Timeout.cpp src/presenters/Instance.cpp ucl/src/gui/Widget.cpp src/model/ActiveCall.cpp src/model/RejectMsgProvider.cpp src/presenters/MoreOptionsPresenter.cpp ucl/src/appfw/SysEventProvider.cpp src/presenters/CallInfoPresenter.cpp src/model/BatteryStateSource.cpp src/model/CallClient.cpp src/model/VoiceControlStateSource.cpp src/model/RssiStateSource.cpp src/model/HdVoiceStateSource.cpp ucl/src/util/logging.cpp src/model/IndicatorStateProvider.cpp src/presenters/KeypadPage.cpp src/presenters/helpers.cpp src/presenters/MotionSensorPresenter.cpp src/main.cpp src/model/MsgClient.cpp src/presenters/IndicatorPresenter.cpp ucl/src/appfw/helpers.cpp src/model/CallUIBuilder.cpp src/presenters/AtspiHighlightHelper.cpp src/presenters/CallStatusPresenter.cpp src/model/ConferenceCallInfo.cpp src/model/HeldCall.cpp src/model/SoundManager.cpp src/model/BluetoothManager.cpp src/model/RejectMsg.cpp src/view/AcceptRejectWidget.cpp ucl/src/appfw/InstanceManagerBase.cpp 
 
 # EDC Sources
 USER_EDCS =  
index 1774f0f3eed8e48e839f508689a9d73a1b0643a3..7e15a90516f2013f5d181d4d835111061ed002b2 100644 (file)
@@ -51,8 +51,6 @@ namespace callui { namespace { namespace impl {
 
        constexpr EdjeSignal SIGNAL_TURN_ON {"turn.on"};
        constexpr EdjeSignal SIGNAL_TURN_OFF {"turn.off"};
-
-       constexpr SmartEvent EVENT_ACCESS_READ_START {"access,read,start"};
 }}}
 
 namespace callui {
@@ -806,7 +804,7 @@ namespace callui {
        {
                auto decrBtn = m_vc->getDecreaseBtn();
                if (decrBtn) {
-                       decrBtn->addEventHandler(impl::EVENT_ACCESS_READ_START,
+                       decrBtn->addEventHandler(ATSPI_HIGHLIGHTED,
                                        WEAK_DELEGATE(AccessoryPresenter::
                                                        onVolumeControlScreenReaderReadStart,
                                                        asWeak(*this)));
@@ -814,7 +812,7 @@ namespace callui {
 
                auto incrBtn = m_vc->getIncreaseBtn();
                if (incrBtn) {
-                       incrBtn->addEventHandler(impl::EVENT_ACCESS_READ_START,
+                       incrBtn->addEventHandler(ATSPI_HIGHLIGHTED,
                                        WEAK_DELEGATE(AccessoryPresenter::
                                                        onVolumeControlScreenReaderReadStart,
                                                        asWeak(*this)));
index d2f512fb359b82589c9db485df7cbba26b58bd6d..04f0ebeca0d34e47c496c2eab38277beb3de4b4c 100644 (file)
@@ -17,6 +17,8 @@
 #include "presenters/KeypadPage.h"
 #include "view/VolumeControl.h"
 
+#include "presenters/AtspiHighlightHelper.h"
+
 #include "resources.h"
 #include "common.h"
 
@@ -156,59 +158,64 @@ namespace callui {
                unregisterCallbacks();
        }
 
+       Result KeypadPage::doPrepare(NaviItem &item)
+       {
+               FAIL_RETURN(createWidget(), "createWidget() failed!");
+
+               FAIL_RETURN(createEntry(), "createEntry() failed!");
+
+               FAIL_RETURN(createButtons(), "createButtons() failed!");
+
+               FAIL_RETURN(createVolumeControl(), "createVolumeControl() failed!");
+
+               registerCallbacks();
+
+               updateVolume(m_sm->getVolume());
+
+               FAIL_RETURN(createAtspiHighlightHelper(),
+                               "createAtspiHighlightHelper() failed!");
+
+               item = getNaviframe().push(*m_widget);
+               if (!item) {
+                       LOG_RETURN(RES_FAIL, "Naviframe::push() failed!");
+               }
+
+               return RES_OK;
+       }
+
        void KeypadPage::onBtnPressed(Widget &widget, void *eventInfo)
        {
-               impl::ButtonInfo *btn =
+               impl::ButtonInfo *info =
                        static_cast<impl::ButtonInfo*>(widget.getData(impl::BTN_DATA_KEY));
-               ILOG("button pressed: %c", *(btn->str));
+               DLOG("Button pressed [%c]", *(info->str));
 
-               if (btn->type == impl::OperationType::DTMF) {
-                       elm_entry_entry_append(*m_entry, btn->str);
+               if (info->type == impl::OperationType::DTMF) {
+                       elm_entry_entry_append(*m_entry, info->str);
                        elm_entry_cursor_end_set(*m_entry);
-                       startDtmf(*(btn->str));
+                       startDtmf(*(info->str));
                }
        }
 
        void KeypadPage::onBtnUnpressed(Widget &widget, void *eventInfo)
        {
-               impl::ButtonInfo *btn =
+               impl::ButtonInfo *info =
                        static_cast<impl::ButtonInfo*>(widget.getData(impl::BTN_DATA_KEY));
-               ILOG("button unpressed: %c", *(btn->str));
+               DLOG("Button unpressed [%c]", *(info->str));
                stopDtmf();
        }
 
        void KeypadPage::onBtnClicked(Widget &widget, void *eventInfo)
        {
-               impl::ButtonInfo *btn =
+               impl::ButtonInfo *info =
                        static_cast<impl::ButtonInfo*>(widget.getData(impl::BTN_DATA_KEY));
 
-               if(btn->type == impl::OperationType::VOLUME) {
-                       ILOG("button clicked: volume");
+               if(info->type == impl::OperationType::VOLUME) {
+                       DLOG("Button clicked [volume]");
                        show(*m_vc);
                        startVCTimer();
-               }
-       }
-
-       Result KeypadPage::doPrepare(NaviItem &item)
-       {
-               FAIL_RETURN(createWidget(), "createWidget() failed!");
-
-               FAIL_RETURN(createEntry(), "createEntry() failed!");
-
-               FAIL_RETURN(createButtons(), "createButtons() failed!");
-
-               FAIL_RETURN(createVolumeControl(), "createVolumeControl() failed!");
 
-               registerCallbacks();
-
-               updateVolume(m_sm->getVolume());
-
-               item = getNaviframe().push(*m_widget);
-               if (!item) {
-                       LOG_RETURN(RES_FAIL, "Naviframe::push() failed!");
+                       elm_atspi_component_highlight_grab(*m_vc);
                }
-
-               return RES_OK;
        }
 
        Result KeypadPage::createWidget()
@@ -222,6 +229,8 @@ namespace callui {
                        LOG_RETURN(RES_FAIL, "Layout::build() failed!");
                }
 
+               setDeactivatorSink(m_widget);
+
                return RES_OK;
        }
 
@@ -263,6 +272,7 @@ namespace callui {
                        }
 
                        buttonSRef = makeShared<StyledWidget>(button);
+                       buttonSRef->bindToEo();
                        buttonSRef->setData(impl::BTN_DATA_KEY, &(impl::buttonsInfo[i]));
                        buttonSRef->setStyle(impl::buttonsInfo[i].style);
 
@@ -280,6 +290,22 @@ namespace callui {
                                                                asWeak(*this)));
                        }
 
+                       // Screen Reader
+                       elm_atspi_accessible_name_cb_set(*buttonSRef,
+                                       [](void *data, Evas_Object *obj) -> char *
+                                       {
+                                               impl::ButtonInfo *info =
+                                                               static_cast<impl::ButtonInfo*>(asWidget(obj)->
+                                                                               getData(impl::BTN_DATA_KEY));
+                                               if (info->type == impl::OperationType::DTMF) {
+                                                       return strdup(info->str);
+                                               } else {
+                                                       return strdup(AO_STR_VOLUME.translate());
+                                               }
+                                               return nullptr;
+                                       },
+                                       this);
+
                        m_widget->setContent(button, impl::buttonsInfo[i].swlPart);
                        show(*buttonSRef);
                }
@@ -326,6 +352,8 @@ namespace callui {
                m_vc->resize(w, h);
                hide(*m_vc);
 
+               registerVolumeControlAo();
+
                return RES_OK;
        }
 
@@ -381,6 +409,12 @@ namespace callui {
                        m_vc->setIncreaseBtnEnable(true);
                        m_vc->setDecreaseBtnEnable(true);
                }
+
+               // Screen Reader
+               if (m_vc->isVisible()) {
+                       elm_atspi_bridge_utils_say(std::to_string(cur).c_str(),
+                                       EINA_FALSE, nullptr, nullptr);
+               }
        }
 
        void KeypadPage::onAudioStateChanged(AudioStateType state)
@@ -417,7 +451,12 @@ namespace callui {
        {
                stopVCTimer();
 
-               m_vcTimer = ecore_timer_add(CALL_VC_TIMER_INTERVAL,
+               auto timerInterval = CALL_VC_TIMER_INTERVAL;
+               if (elm_atspi_bridge_utils_is_screen_reader_enabled()) {
+                       timerInterval = CALL_VC_SCREEN_READER_TIMER_INTERVAL;
+               }
+
+               m_vcTimer = ecore_timer_add(timerInterval,
                                CALLBACK_B(KeypadPage::onVCTimerCb),
                                this);
        }
@@ -503,4 +542,118 @@ namespace callui {
                m_sm->delVolumeStateHandler(DELEGATE(
                                KeypadPage::onVolumeLevelChanged, this));
        }
+
+       // Screen Reader
+       Result KeypadPage::createAtspiHighlightHelper()
+       {
+               m_atspiHelper = AtspiHighlightHelper::newInstance(*this, getWindow());
+               if (!m_atspiHelper) {
+                       LOG_RETURN(RES_FAIL,
+                                       "AtspiHighlightHelper::newInstance() failed!");
+               }
+
+               m_atspiHelper->setRelationEventHandler(WEAK_DELEGATE(
+                               KeypadPage::onAtspiHighlight, asWeak(*this)));
+
+               m_atspiHelper->registerWidget(*getFirstButton());
+               m_atspiHelper->registerWidget(*getLastButton());
+               m_atspiHelper->registerWidget(*m_vc.get());
+               m_atspiHelper->registerWidget(*m_vc->getDecreaseBtn());
+               m_atspiHelper->registerWidget(*m_vc->getIncreaseBtn());
+               m_atspiHelper->registerWidget(*m_vc->getValueTxtAo());
+
+               return RES_OK;
+       }
+
+       Elm_Interface_Atspi_Accessible *KeypadPage::onAtspiHighlight(
+                               Elm_Interface_Atspi_Accessible *ao,
+                               Elm_Atspi_Relation_Type flowRelation)
+       {
+               DLOG("FlowRelation [%s]",
+                               flowRelation == ELM_ATSPI_RELATION_FLOWS_FROM ?
+                                               "FROM" : "TO");
+
+               auto firstBtn = getFirstButton();
+               auto lastBtn = getLastButton();
+               auto vcLayout = m_vc.get();
+               auto vcDecrVolumeBtn = m_vc->getDecreaseBtn();
+               auto vcIncrVolumeBtn = m_vc->getIncreaseBtn();
+               auto vcVolumeValueAo = m_vc->getValueTxtAo();
+
+               if (ao == *firstBtn) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_TO) {
+                               return nullptr;
+                       }
+               } else if (ao == *lastBtn) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_FROM) {
+                               return nullptr;
+                       }
+               } else if (ao == *vcLayout) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_TO) {
+                               return *vcDecrVolumeBtn;
+                       }
+               } else if (ao == *vcDecrVolumeBtn) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_TO) {
+                               return *vcVolumeValueAo;
+                       } else {
+                               return *vcLayout;
+                       }
+               } else if (ao == *vcVolumeValueAo) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_TO) {
+                               return *vcIncrVolumeBtn;
+                       } else {
+                               return *vcDecrVolumeBtn;
+                       }
+               } else if (ao == *vcIncrVolumeBtn) {
+                       if (flowRelation == ELM_ATSPI_RELATION_FLOWS_FROM) {
+                               return *vcVolumeValueAo;
+                       }
+               } else if (ao == getWindow()) {
+                       return *firstBtn;
+               } else {
+                       LOG_RETURN_VALUE(RES_FAIL, nullptr, "Unknown object!");
+               }
+
+               return ao;
+       }
+
+       ElmWidget *KeypadPage::getFirstButton()
+       {
+               return dynamicWidgetCast<ElmWidget>(
+                               m_widget->getContent(impl::buttonsInfo[0].swlPart));
+       }
+
+       ElmWidget *KeypadPage::getLastButton()
+       {
+               return dynamicWidgetCast<ElmWidget>(
+                               m_widget->getContent(impl::buttonsInfo[(
+                                               impl::KEYPAD_BTN_MAX_COUNT - 1)].swlPart));
+       }
+
+       void KeypadPage::registerVolumeControlAo()
+       {
+               auto decrBtn = m_vc->getDecreaseBtn();
+
+               if (decrBtn) {
+                       decrBtn->addEventHandler(ATSPI_HIGHLIGHTED,
+                                       WEAK_DELEGATE(KeypadPage::
+                                                       onVolumeControlScreenReaderReadStart,
+                                                       asWeak(*this)));
+               }
+
+               auto incrBtn = m_vc->getIncreaseBtn();
+               if (incrBtn) {
+                       incrBtn->addEventHandler(ATSPI_HIGHLIGHTED,
+                                       WEAK_DELEGATE(KeypadPage::
+                                                       onVolumeControlScreenReaderReadStart,
+                                                       asWeak(*this)));
+               }
+       }
+
+       void KeypadPage::onVolumeControlScreenReaderReadStart(
+                       Widget &widget,
+                       void *eventInfo)
+       {
+               restartVCTimer();
+       }
 }
index 6e6cd0b2241754a71cd13731b3d595adb95cb61a..7c795fe91e2abf2cbaf1d548219b5743f33253e4 100644 (file)
@@ -36,6 +36,7 @@
 namespace callui {
 
        constexpr ucl::SmartEvent BTN_CLICKED {"clicked"};
+       constexpr ucl::SmartEvent ATSPI_HIGHLIGHTED {"atspi,highlighted"};
 }
 
 #endif // __CALLUI_VIEW_COMMON_H__