TizenRefApp-8640 [Gallery] Implement custom accessibility order in 86/132986/2
authorIgor Nazarov <i.nazarov@samsung.com>
Thu, 8 Jun 2017 13:51:29 +0000 (16:51 +0300)
committerIgor Nazarov <i.nazarov@samsung.com>
Thu, 8 Jun 2017 13:55:55 +0000 (16:55 +0300)
ThumbnailPage

- Implemented AtspiHighlightHelper presenter class;
- Fixed bug in ImageGrid with double highlight on swipe;
- Other changes.

Change-Id: I92ede1fc87a81750269b0742be6e52001ab81c2f

15 files changed:
inc/presenters/AtspiHighlightHelper.h [new file with mode: 0644]
inc/presenters/Presenter.h
inc/presenters/ThumbnailPage.h
inc/view/ImageGrid.h
inc/view/helpers.h
src/presenters/AtspiHighlightHelper.cpp [new file with mode: 0644]
src/presenters/MoreOptionsPresenter.cpp
src/presenters/Presenter.cpp
src/presenters/ProcessingPresenter.cpp
src/presenters/ThumbnailPage.cpp
src/presenters/VideoPlayerPage.cpp
src/view/ImageGrid.cpp
src/view/helpers.cpp
ucl/inc/ucl/gui/types.h
ucl/src/gui/ElmWidget.cpp

diff --git a/inc/presenters/AtspiHighlightHelper.h b/inc/presenters/AtspiHighlightHelper.h
new file mode 100644 (file)
index 0000000..b84471e
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 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 __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
+#define __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
+
+#include "Presenter.h"
+
+namespace gallery {
+
+       UCL_DECLARE_REF_ALIASES(AtspiHighlightHelper);
+
+       class AtspiHighlightHelper final : public Presenter {
+       public:
+               using EventHandler = ucl::WeakDelegate<Elm_Interface_Atspi_Accessible *(
+                               ucl::Widget &widget, Elm_Atspi_Relation_Type flowRelation)>;
+
+       public:
+               static AtspiHighlightHelperSRef newInstance(ucl::ElmWidget &rootWidget);
+
+               void setEventHandler(EventHandler handler);
+               void registerWidget(ucl::ElmWidget &widget);
+
+       private:
+               friend class ucl::RefCountObj<AtspiHighlightHelper>;
+               AtspiHighlightHelper(ucl::RefCountObjBase &rc);
+               virtual ~AtspiHighlightHelper();
+
+               ucl::Result prepare(ucl::ElmWidget &rootWidget);
+
+       private:
+               void onAtspiGesture(ucl::Widget &widget, void *eventInfo);
+
+       private:
+               EventHandler m_eventHandler;
+       };
+}
+
+#endif // __GALLERY_PRESENTERS_ATSPI_HIGHLIGH_HELPER_H__
index 2366f5b1a22c049150319208689a497930ec7f28..b0fe70ef9dfb6ba9b42bbe7ded8a2d662801c114 100644 (file)
@@ -46,6 +46,7 @@ namespace gallery {
                ucl::Result prepare(ucl::ElmWidget &widget);
 
                ucl::Window &getWindow();
+               bool isWindowReady() const;
 
                void addDeactivatorSource(ucl::Widget &source);
                void addDeactivatorException(void *deactivator);
index ca5431c40679bc1bd5e806edf3afa641e736e649..626ab183bb1ba4ed2949a167de1d40ca7906bec5 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "view/IImageGridListener.h"
 
+#include "AtspiHighlightHelper.h"
 #include "IMoreOptionsListener.h"
 
 namespace gallery {
@@ -58,7 +59,10 @@ namespace gallery {
 
                void onPageExitRequest(Page &page);
 
-               // Page //
+               Elm_Interface_Atspi_Accessible *onAtspiHighlight(
+                               ucl::Widget &widget, Elm_Atspi_Relation_Type flowRelation);
+
+               // Presenter //
 
                virtual void onActivateBy(const DeactivatorInfo &info) final override;
                virtual void onDeactivateBy(const DeactivatorInfo &info) final override;
@@ -88,6 +92,7 @@ namespace gallery {
                PageContentSRef m_content;
                ImageGridSRef m_imageGrid;
                MoreOptionsPresenterSRef m_more;
+               AtspiHighlightHelperSRef m_atspiHelper;
 
                PageWRef m_page;
        };
index 540cafa8e819b0839d2cb8c49c8864f3767d9fea..054f880e024e29d22a8d23c8aace90e99bbd9c0a 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <deque>
 
-#include "ucl/gui/Layout.h"
 #include "ucl/gui/StyledWidget.h"
 
 #include "ucl/misc/Timeout.h"
@@ -264,7 +263,7 @@ namespace gallery {
                bool m_isInSelectMode;
                bool m_isRotaryActive;
 
-               ucl::LayoutSRef m_highlighKeeper;
+               ucl::ElmWidgetSRef m_highlighKeeper;
                ucl::TimeoutSRef m_highlightTimeout;
                int m_highlightID;
                bool m_isHighlightLocked;
index 58175a2adbbb4fc30ebd1761cd35aa7ac102937c..5a13ab4f8cc76e929458478deb958eae49b27f33 100644 (file)
 #ifndef __GALLERY_VIEW_HELPERS_H__
 #define __GALLERY_VIEW_HELPERS_H__
 
-#include "types.h"
-
-namespace ucl {
+#include "ucl/gui/Naviframe.h"
 
-       class ElmWidget;
-       class Naviframe;
-}
+#include "types.h"
 
 namespace gallery { namespace util {
 
        ucl::Result createCircleSurface(ucl::Naviframe &navi);
        Eext_Circle_Surface *getCircleSurface(const ucl::ElmWidget &widget);
+
+       ucl::ElmWidgetSRef createFakeAccessObject(ucl::ElmWidget &parent);
 }}
 
 namespace gallery {
diff --git a/src/presenters/AtspiHighlightHelper.cpp b/src/presenters/AtspiHighlightHelper.cpp
new file mode 100644 (file)
index 0000000..feac2d2
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2017 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 "presenters/AtspiHighlightHelper.h"
+
+#include "common.h"
+
+namespace gallery { namespace { namespace impl {
+
+       using namespace ucl;
+
+       constexpr EoDataKey ATSPI_HELPER_DATA {"gallery,atspi,highlight,helper"};
+}}}
+
+namespace gallery {
+
+       using namespace ucl;
+
+       AtspiHighlightHelperSRef AtspiHighlightHelper::newInstance(
+                       ElmWidget &rootWidget)
+       {
+               auto result = makeShared<AtspiHighlightHelper>();
+
+               FAIL_RETURN_VALUE(result->prepare(rootWidget), {},
+                               "result->prepare() failed!");
+
+               return result;
+       }
+
+       AtspiHighlightHelper::AtspiHighlightHelper(RefCountObjBase &rc) :
+               Presenter(rc)
+       {
+       }
+
+       AtspiHighlightHelper::~AtspiHighlightHelper()
+       {
+       }
+
+       Result AtspiHighlightHelper::prepare(ElmWidget &rootWidget)
+       {
+               FAIL_RETURN(Presenter::prepare(rootWidget),
+                               "Presenter::prepare() failed!");
+
+               registerWidget(rootWidget);
+
+               return RES_OK;
+       }
+
+       void AtspiHighlightHelper::setEventHandler(EventHandler handler)
+       {
+               m_eventHandler = handler;
+       }
+
+       void AtspiHighlightHelper::registerWidget(ElmWidget &widget)
+       {
+               widget.addEventHandler(ATSPI_ON_GESTURE, WEAK_DELEGATE(
+                               AtspiHighlightHelper::onAtspiGesture, asWeak(*this)));
+       }
+
+       void AtspiHighlightHelper::onAtspiGesture(
+                       Widget &widget, void *eventInfo)
+       {
+               auto &e = *static_cast<AtspiGestureEventInfo *>(eventInfo);
+               if (e.stopPropagation) {
+                       return;
+               }
+               if (!isActive()) {
+                       e.preventDefault = true;
+                       return;
+               }
+
+               e.preventDefault = false;
+               e.stopPropagation = true;
+
+               if (!m_eventHandler) {
+                       return;
+               }
+               const Elm_Atspi_Relation_Type relation = getFlowRelation(e.gestureInfo);
+               if (relation == ELM_ATSPI_RELATION_NULL) {
+                       return;
+               }
+               const auto relationObj = m_eventHandler(widget, relation);
+               if (!relationObj) {
+                       return;
+               }
+
+               auto &win = getWindow();
+               auto atspiHelper = static_cast<Elm_Interface_Atspi_Accessible *>
+                               (win.getData(impl::ATSPI_HELPER_DATA));
+
+               if (!atspiHelper) {
+                       const auto obj = util::createFakeAccessObject(win);
+                       if (!obj) {
+                               LOG_RETURN_VOID(RES_FAIL, "createFakeAccessObject() failed!");
+                       }
+                       obj->setIsOwner(false);
+                       atspiHelper = obj->getEo();
+                       win.setData(impl::ATSPI_HELPER_DATA, atspiHelper);
+               }
+
+               elm_atspi_component_highlight_grab(atspiHelper);
+
+               elm_atspi_accessible_relationships_clear(atspiHelper);
+               elm_atspi_accessible_relationship_append(atspiHelper,
+                               relation, relationObj);
+       }
+}
index 4e7379f9a0a10022c83b1d468281072f6aaeac18..351cedae961c68099906cba90acfaa063d8e45f4 100644 (file)
@@ -146,6 +146,7 @@ namespace gallery {
                m_widget->addEventHandler(impl::MORE_ITEM_SELECTED, WEAK_DELEGATE(
                                MoreOptionsPresenter::onItemSelected, asWeak(*this)));
 
+               addDeactivatorException(this);
                deactivateBy(m_widget.get());
 
                return RES_OK;
index dd29ddb8c073b505c2a1b4fd6280474ce0541abd..814c4ac675282f3f3aa329330d965efec91c418c 100644 (file)
@@ -56,9 +56,15 @@ namespace gallery {
 
        Window &Presenter::getWindow()
        {
+               UCL_ASSERT(isWindowReady(), "m_window is NULL!");
                return *m_window;
        }
 
+       bool Presenter::isWindowReady() const
+       {
+               return !!m_window;
+       }
+
        void Presenter::addDeactivatorSource(Widget &source)
        {
                source.addEventHandler(impl::ACTIVATE_BY,
index 96596f73e3c898dd259be28c578504143706b5fc..bccd4cb44447e23e5a65abf6a24df453d5544b4e 100644 (file)
@@ -274,11 +274,12 @@ namespace gallery {
                        eext_object_event_callback_del(*m_popup, EEXT_CALLBACK_BACK,
                                        CALLBACK_A(ProcessingPresenter::onPopupHWBackKey));
 
-                       m_popup.reset();
-
                        deactivateBy(m_popup.get());
                        broadcastActivateBy(this);
-                       m_rc->unref();
+                       m_popup.reset();
+                       if (m_isComplete) {
+                               m_rc->unref();
+                       }
                }
        }
 
index 0114b4c28f5332cf8c28d8139364dba49d8b8b94..5cf6e5b2d89dbc29676c21803b4c45aa42b65eeb 100644 (file)
@@ -210,12 +210,18 @@ namespace gallery {
                        }),
                        "Page::prepare() failed!");
 
+               m_atspiHelper = AtspiHighlightHelper::newInstance(getWindow());
+               if (!m_atspiHelper) {
+                       LOG_RETURN(RES_FAIL, "AtspiHighlightHelper::newInstance() failed!");
+               }
+
                m_imageGrid->setItemCount(m_mediaItems.size());
 
                m_album->addChangeHandler(WEAK_DELEGATE(
                                ThumbnailPage::onAlbumChanged, asWeak(*this)));
 
-               m_more->setListener(asWeakThis<IMoreOptionsListener>(this));
+               m_atspiHelper->setEventHandler(WEAK_DELEGATE(
+                               ThumbnailPage::onAtspiHighlight, asWeak(*this)));
 
                return RES_OK;
        }
@@ -240,8 +246,13 @@ namespace gallery {
                                        impl::PAGE_SCROLL_IN_FRICTION);
                        elm_config_scroll_bring_in_scroll_friction_set(
                                        impl::BRING_IN_SCROLL_FRICTION);
+               }
 
+               if (!info.isBroadcast) {
                        m_more->activateBy(info.deactivator);
+                       if (m_atspiHelper) {
+                               m_atspiHelper->activateBy(info.deactivator);
+                       }
                }
 
                if (isActive()) {
@@ -251,13 +262,20 @@ namespace gallery {
 
        void ThumbnailPage::onDeactivateBy(const DeactivatorInfo &info)
        {
-               if (info.deactivator == &getNaviframe()) {
+               if (!info.isBroadcast) {
                        m_more->deactivateBy(info.deactivator);
+                       m_atspiHelper->deactivateBy(info.deactivator);
                }
 
                m_imageGrid->deactivateRotary();
        }
 
+       Elm_Interface_Atspi_Accessible *ThumbnailPage::onAtspiHighlight(
+                               Widget &widget, Elm_Atspi_Relation_Type flowRelation)
+       {
+               return m_imageGrid->getAccessObject(true);
+       }
+
        void ThumbnailPage::onItemRealized(const int itemIndex)
        {
                m_realizedItems.emplace_back(new RealizedItem(*this, itemIndex));
index d0876737b81e9e2a75829777f36b5a907b75a019..8d367af2dea7d34755e28a9ccdee917604aaf9e7 100644 (file)
@@ -152,7 +152,9 @@ namespace gallery {
 
        VideoPlayerPage::~VideoPlayerPage()
        {
-               setScreenAlwaysOn(false);
+               if (isWindowReady()) {
+                       setScreenAlwaysOn(false);
+               }
 
                delRotaryEventHandler(CALLBACK_A(VideoPlayerPage::onRotary), this);
 
index 278a745926e1ed9e49249e79693d5999f8db07a1..09421c523d3a4cb4579de627a6623146eb89d3b7 100644 (file)
@@ -54,9 +54,6 @@ namespace gallery { namespace { namespace impl {
        constexpr EdjeSignal BTN_UNBLOCK_CLICKS {"gallery,unblock,clicks"};
 
        // Other //
-       constexpr LayoutTheme LAYOUT_FAKE_ACCESS_OBJECT
-                       {"layout", "gallery", "fake_access_object"};
-
        constexpr auto HCOMB_SCROLL_LIMIT = 1000;
        constexpr auto SCROLL_HIGHLIGHT_TIMEOUT_SEC = 0.1;
 
@@ -350,7 +347,8 @@ namespace gallery {
                                        return;
                                }
 
-                               if (m_isHighlighted && m_imageGrid.m_highlightTimeout) {
+                               if ((m_imageGrid.m_highlightID == m_realizeIndex) &&
+                                               m_imageGrid.m_highlightTimeout) {
                                        m_imageGrid.m_isHighlightLocked = true;
                                        elm_atspi_component_highlight_clear(m_btn);
                                }
@@ -549,10 +547,6 @@ namespace gallery {
 
                        void onHighlighted(Widget &widget, void *eventInfo)
                        {
-                               if (m_isHighlighted) {
-                                       return;
-                               }
-                               m_isHighlighted = true;
                                if (!isRealized()) {
                                        LOG_RETURN_VOID(RES_ILLEGAL_STATE, "Item is not realized!");
                                }
@@ -561,10 +555,6 @@ namespace gallery {
 
                        void onUnhighlighted(Widget &widget, void *eventInfo)
                        {
-                               if (!m_isHighlighted) {
-                                       return;
-                               }
-                               m_isHighlighted = false;
                                if (!isRealized()) {
                                        LOG_RETURN_VOID(RES_ILLEGAL_STATE, "Item is not realized!");
                                }
@@ -618,7 +608,6 @@ namespace gallery {
                        bool m_isImageLoaded = false;
                        bool m_isClicksBlocked = false;
                        bool m_isSelected = false;
-                       bool m_isHighlighted = false;
                };
 
        public:
@@ -902,24 +891,9 @@ namespace gallery {
 
        void ImageGrid::createHighlighKeeper()
        {
-               m_highlighKeeper = Layout::Builder().
-                               setTheme(impl::LAYOUT_FAKE_ACCESS_OBJECT).
-                               setIsOwner(true).
-                               build(*m_box.getWindow());
+               m_highlighKeeper = util::createFakeAccessObject(*m_box.getWindow());
                UCL_ASSERT(m_highlighKeeper, "m_highlighKeeper is NULL");
 
-               m_highlighKeeper->setGeometry(0, 0, 1, 1);
-               show(*m_highlighKeeper);
-
-               elm_atspi_accessible_reading_info_type_set(*m_highlighKeeper, 0);
-
-               elm_atspi_accessible_gesture_cb_set(*m_highlighKeeper,
-                       [](void *, Elm_Atspi_Gesture_Info, Evas_Object *) -> Eina_Bool
-                       {
-                               return EINA_TRUE;
-                       },
-                       nullptr);
-
                m_highlighKeeper->addEventHandler(ATSPI_UNHIGHLIGHTED,
                                WEAK_DELEGATE(ImageGrid::onKeeperUnhighlighted, asWeak(*this)));
        }
@@ -1331,8 +1305,6 @@ namespace gallery {
                        } else {
                                m_highlightTimeout.reset();
                        }
-               } else {
-                       WLOG("Item was not highlighted: %d.", itemIndex);
                }
        }
 
@@ -1390,7 +1362,7 @@ namespace gallery {
                                elm_atspi_component_highlight_grab(
                                                slot.getItemAtspi(itemOffset));
                                return RES_OK;
-                       }), "Failed to get item Atspi!");
+                       }), "Failed to Grab item highlight!");
        }
 
        Elm_Interface_Atspi_Accessible *ImageGrid::requestAtspi(const int itemIndex)
@@ -1402,7 +1374,19 @@ namespace gallery {
                        }
                        return nullptr;
                }
-               return getItemAtspi(itemIndex);
+
+               const int oldHighlightID = m_highlightID;
+               m_highlightID = itemIndex; // To prevent autohighlight timer to start
+
+               const auto result = getItemAtspi(itemIndex);
+               if (!result) {
+                       m_highlightID = oldHighlightID;
+                       return nullptr;
+               }
+
+               m_highlightTimeout.reset();
+
+               return result;
        }
 
        Elm_Interface_Atspi_Accessible *ImageGrid::getItemAtspi(
@@ -1761,11 +1745,11 @@ namespace gallery {
                ++m_eventsLock;
 
                if (updateScrollOffset()) {
+                       updateHighlightTimeout();
                        if (updateBeginSlotIndex()) {
                                realizeSlots();
                                updateRectMins();
                        }
-                       updateHighlightTimeout();
                }
 
                --m_eventsLock;
index 14ad066acd9c5ab0bb0f55e740034d173281ac25..9add4e70f7bef7b20db0c4b3f56ab9c26768da4b 100644 (file)
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "ucl/gui/Window.h"
-#include "ucl/gui/Naviframe.h"
+#include "ucl/gui/Layout.h"
 
 #include "common.h"
 
@@ -28,6 +28,9 @@ namespace gallery { namespace { namespace impl {
        using namespace ucl;
 
        constexpr EoDataKey CIRCLE_SURFACE {"gallery,eext,circle,surface"};
+
+       constexpr LayoutTheme LAYOUT_FAKE_ACCESS_OBJECT
+                       {"layout", "gallery", "fake_access_object"};
 }}}
 
 namespace gallery { namespace util {
@@ -73,6 +76,32 @@ namespace gallery { namespace util {
 
                return sfc;
        }
+
+       ElmWidgetSRef createFakeAccessObject(ElmWidget &parent)
+       {
+               const auto result = Layout::Builder().
+                               setTheme(impl::LAYOUT_FAKE_ACCESS_OBJECT).
+                               setIsOwner(true).
+                               setNeedBindToEo(true).
+                               build(parent);
+               if (!result) {
+                       LOG_RETURN_VALUE(RES_FAIL, {}, "Layout::build() failed!");
+               }
+
+               result->setGeometry(0, 0, 1, 1);
+               show(*result);
+
+               elm_atspi_accessible_reading_info_type_set(*result, 0);
+
+               elm_atspi_accessible_gesture_cb_set(*result,
+                       [](void *, Elm_Atspi_Gesture_Info, Evas_Object *) -> Eina_Bool
+                       {
+                               return EINA_TRUE;
+                       },
+                       nullptr);
+
+               return result;
+       }
 }}
 
 namespace gallery {
index 2a8dac56fafb785b551ffd1389a80ec3fb8b8c17..454b6bc8cfbd7d96838399a49959f41e36eee569 100644 (file)
@@ -92,6 +92,7 @@ namespace ucl {
        struct AtspiGestureEventInfo {
                Elm_Atspi_Gesture_Info gestureInfo;
                bool preventDefault;
+               bool stopPropagation;
        };
 
        // WidgetARHint //
index ef8259321277d82a555b1585fb999ce5679f12ad..73856be8d07b6e0e53926a92b8360856d64ac5d7 100644 (file)
@@ -63,7 +63,7 @@ namespace ucl {
        Eina_Bool ElmWidget::onAtspiGesture(Elm_Atspi_Gesture_Info gestureInfo,
                                        Evas_Object *obj)
        {
-               AtspiGestureEventInfo eventInfo{gestureInfo, false};
+               AtspiGestureEventInfo eventInfo{gestureInfo};
                callEvent(ATSPI_ON_GESTURE, &eventInfo);
                return toEina(eventInfo.preventDefault);
        }