X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Fdevel-api%2Fadaptor-framework%2Faccessibility.cpp;h=f69c96cdc768806952b25f6658ba5a8ad6cb10ac;hb=HEAD;hp=cea55f38e2fc3e27ae8f0323319279bd1d3c84f3;hpb=92b27f0387165cef0c0cc3278e7c208c7eb5c4bd;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/devel-api/adaptor-framework/accessibility.cpp b/dali/devel-api/adaptor-framework/accessibility.cpp index cea55f3..6caf3d8 100644 --- a/dali/devel-api/adaptor-framework/accessibility.cpp +++ b/dali/devel-api/adaptor-framework/accessibility.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2020 Samsung Electronics Co., Ltd + * Copyright 2022 Samsung Electronics Co., Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,9 +31,21 @@ #include #include #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include #include using namespace Dali::Accessibility; @@ -185,6 +197,102 @@ std::string Accessible::GetRoleName() const return std::string{it->second}; } +AtspiInterfaces Accessible::GetInterfaces() const +{ + if(!mInterfaces) + { + mInterfaces = DoGetInterfaces(); + DALI_ASSERT_DEBUG(mInterfaces); // There has to be at least AtspiInterface::ACCESSIBLE + } + + return mInterfaces; +} + +std::vector Accessible::GetInterfacesAsStrings() const +{ + std::vector ret; + AtspiInterfaces interfaces = GetInterfaces(); + + for(std::size_t i = 0u; i < static_cast(AtspiInterface::MAX_COUNT); ++i) + { + auto interface = static_cast(i); + + if(interfaces[interface]) + { + auto name = GetInterfaceName(interface); + + DALI_ASSERT_DEBUG(!name.empty()); + ret.emplace_back(std::move(name)); + } + } + + return ret; +} + +AtspiInterfaces Accessible::DoGetInterfaces() const +{ + AtspiInterfaces interfaces; + + interfaces[AtspiInterface::ACCESSIBLE] = true; + interfaces[AtspiInterface::ACTION] = dynamic_cast(this); + interfaces[AtspiInterface::APPLICATION] = dynamic_cast(this); + interfaces[AtspiInterface::COLLECTION] = dynamic_cast(this); + interfaces[AtspiInterface::COMPONENT] = dynamic_cast(this); + interfaces[AtspiInterface::EDITABLE_TEXT] = dynamic_cast(this); + interfaces[AtspiInterface::HYPERLINK] = dynamic_cast(this); + interfaces[AtspiInterface::HYPERTEXT] = dynamic_cast(this); + interfaces[AtspiInterface::SELECTION] = dynamic_cast(this); + interfaces[AtspiInterface::SOCKET] = dynamic_cast(this); + interfaces[AtspiInterface::TABLE] = dynamic_cast(this); + interfaces[AtspiInterface::TABLE_CELL] = dynamic_cast(this); + interfaces[AtspiInterface::TEXT] = dynamic_cast(this); + interfaces[AtspiInterface::VALUE] = dynamic_cast(this); + + return interfaces; +} + +std::string Accessible::GetInterfaceName(AtspiInterface interface) +{ + static const std::unordered_map interfaceMap{ + {AtspiInterface::ACCESSIBLE, "org.a11y.atspi.Accessible"}, + {AtspiInterface::ACTION, "org.a11y.atspi.Action"}, + {AtspiInterface::APPLICATION, "org.a11y.atspi.Application"}, + {AtspiInterface::CACHE, "org.a11y.atspi.Cache"}, + {AtspiInterface::COLLECTION, "org.a11y.atspi.Collection"}, + {AtspiInterface::COMPONENT, "org.a11y.atspi.Component"}, + {AtspiInterface::DEVICE_EVENT_CONTROLLER, "org.a11y.atspi.DeviceEventController"}, + {AtspiInterface::DEVICE_EVENT_LISTENER, "org.a11y.atspi.DeviceEventListener"}, + {AtspiInterface::DOCUMENT, "org.a11y.atspi.Document"}, + {AtspiInterface::EDITABLE_TEXT, "org.a11y.atspi.EditableText"}, + {AtspiInterface::EVENT_DOCUMENT, "org.a11y.atspi.Event.Document"}, + {AtspiInterface::EVENT_FOCUS, "org.a11y.atspi.Event.Focus"}, + {AtspiInterface::EVENT_KEYBOARD, "org.a11y.atspi.Event.Keyboard"}, + {AtspiInterface::EVENT_MOUSE, "org.a11y.atspi.Event.Mouse"}, + {AtspiInterface::EVENT_OBJECT, "org.a11y.atspi.Event.Object"}, + {AtspiInterface::EVENT_TERMINAL, "org.a11y.atspi.Event.Terminal"}, + {AtspiInterface::EVENT_WINDOW, "org.a11y.atspi.Event.Window"}, + {AtspiInterface::HYPERLINK, "org.a11y.atspi.Hyperlink"}, + {AtspiInterface::HYPERTEXT, "org.a11y.atspi.Hypertext"}, + {AtspiInterface::IMAGE, "org.a11y.atspi.Image"}, + {AtspiInterface::REGISTRY, "org.a11y.atspi.Registry"}, + {AtspiInterface::SELECTION, "org.a11y.atspi.Selection"}, + {AtspiInterface::SOCKET, "org.a11y.atspi.Socket"}, + {AtspiInterface::TABLE, "org.a11y.atspi.Table"}, + {AtspiInterface::TABLE_CELL, "org.a11y.atspi.TableCell"}, + {AtspiInterface::TEXT, "org.a11y.atspi.Text"}, + {AtspiInterface::VALUE, "org.a11y.atspi.Value"}, + }; + + auto it = interfaceMap.find(interface); + + if(it == interfaceMap.end()) + { + return {}; + } + + return std::string{it->second}; +} + Dali::Actor Accessible::GetCurrentlyHighlightedActor() { return IsUp() ? Bridge::GetCurrentBridge()->mData->mCurrentlyHighlightedActor : Dali::Actor{}; @@ -198,6 +306,13 @@ void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor) } } +bool Accessible::IsHighlighted() const +{ + Dali::Actor self = GetInternalActor(); + + return self && self == GetCurrentlyHighlightedActor(); +} + Dali::Actor Accessible::GetHighlightActor() { return IsUp() ? Bridge::GetCurrentBridge()->mData->mHighlightActor : Dali::Actor{}; @@ -234,6 +349,9 @@ namespace { class AdaptorAccessible : public ActorAccessible { +private: + std::unique_ptr mRenderNotification = nullptr; + protected: bool mRoot = false; @@ -251,12 +369,68 @@ public: bool GrabHighlight() override { - return false; + if(!IsUp()) + { + return false; + } + + // Only window accessible is able to grab and clear highlight + if(!mRoot) + { + return false; + } + + auto self = Self(); + auto oldHighlightedActor = GetCurrentlyHighlightedActor(); + if(self == oldHighlightedActor) + { + return true; + } + + // Clear the old highlight. + if(oldHighlightedActor) + { + auto oldHighlightedObject = Dali::Accessibility::Component::DownCast(Accessible::Get(oldHighlightedActor)); + if(oldHighlightedObject) + { + oldHighlightedObject->ClearHighlight(); + } + } + + SetCurrentlyHighlightedActor(self); + + auto window = Dali::DevelWindow::Get(self); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + windowImpl.EmitAccessibilityHighlightSignal(true); + + return true; } bool ClearHighlight() override { - return false; + if(!IsUp()) + { + return false; + } + + // Only window accessible is able to grab and clear highlight + if(!mRoot) + { + return false; + } + + if(!IsHighlighted()) + { + return false; + } + + SetCurrentlyHighlightedActor({}); + + auto window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + windowImpl.EmitAccessibilityHighlightSignal(false); + + return true; } Role GetRole() const override @@ -277,22 +451,36 @@ public: state[State::VISIBLE] = true; state[State::ACTIVE] = visible; } - else + else if(GetParent()) { auto parentState = GetParent()->GetStates(); state[State::SHOWING] = parentState[State::SHOWING]; state[State::VISIBLE] = parentState[State::VISIBLE]; } + else + { + state[State::SHOWING] = false; + state[State::VISIBLE] = false; + } return state; } Attributes GetAttributes() const override { + Attributes attributes; + + if(mRoot) + { + Dali::Window window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + attributes["resID"] = windowImpl.GetNativeResourceId(); + } + Dali::TypeInfo type; Self().GetTypeInfo(type); - return { - {"class", type.GetName()}, - }; + attributes["class"] = type.GetName(); + + return attributes; } bool DoGesture(const GestureInfo& gestureInfo) override @@ -304,14 +492,50 @@ public: { return {}; } + + void SetListenPostRender(bool enabled) override + { + if(!mRoot) + { + return; + } + + auto window = Dali::DevelWindow::Get(Self()); + Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation(window); + + if(!mRenderNotification) + { + mRenderNotification = std::unique_ptr( + TriggerEventFactory::CreateTriggerEvent(MakeCallback(this, &AdaptorAccessible::OnPostRender), + TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER)); + } + + if(enabled) + { + windowImpl.SetRenderNotification(mRenderNotification.get()); + } + else + { + windowImpl.SetRenderNotification(nullptr); + } + } + + void OnPostRender() + { + Accessibility::Bridge::GetCurrentBridge()->EmitPostRender(shared_from_this()); + } }; // AdaptorAccessible -using AdaptorAccessiblesType = std::unordered_map >; +using AdaptorAccessiblesType = std::unordered_map>; // Save RefObject from an Actor in Accessible::Get() -AdaptorAccessiblesType gAdaptorAccessibles; +AdaptorAccessiblesType& GetAdaptorAccessibles() +{ + static AdaptorAccessiblesType gAdaptorAccessibles; + return gAdaptorAccessibles; +} -std::function convertingFunctor = [](Dali::Actor) -> Accessible* { +std::function(Dali::Actor)> convertingFunctor = [](Dali::Actor) -> std::shared_ptr { return nullptr; }; @@ -322,16 +546,16 @@ void Accessible::SetObjectRegistry(ObjectRegistry registry) { objectRegistry = registry; objectRegistry.ObjectDestroyedSignal().Connect([](const Dali::RefObject* obj) { - gAdaptorAccessibles.erase(obj); + GetAdaptorAccessibles().erase(obj); }); } -void Accessible::RegisterExternalAccessibleGetter(std::function functor) +void Accessible::RegisterExternalAccessibleGetter(std::function(Dali::Actor)> functor) { convertingFunctor = functor; } -Accessible* Accessible::Get(Dali::Actor actor, bool isRoot) +std::shared_ptr Accessible::GetOwningPtr(Dali::Actor actor) { if(!actor) { @@ -341,13 +565,25 @@ Accessible* Accessible::Get(Dali::Actor actor, bool isRoot) auto accessible = convertingFunctor(actor); if(!accessible) { - auto pair = gAdaptorAccessibles.emplace(&actor.GetBaseObject(), nullptr); + auto pair = GetAdaptorAccessibles().emplace(&actor.GetBaseObject(), nullptr); if(pair.second) { + bool isRoot = false; + Dali::Integration::Scene scene = Dali::Integration::Scene::Get(actor); + if(scene) + { + isRoot = (actor == scene.GetRootLayer()); + } pair.first->second.reset(new AdaptorAccessible(actor, isRoot)); } - accessible = pair.first->second.get(); + accessible = pair.first->second; } return accessible; } + +Accessible* Accessible::Get(Dali::Actor actor) +{ + auto accessible = Accessible::GetOwningPtr(actor); + return accessible ? accessible.get() : nullptr; +} \ No newline at end of file