From: David Steele Date: Fri, 30 Oct 2020 13:19:09 +0000 (+0000) Subject: Merge changes I2df640e0,Ia1188305,I7fae506e,I7967a7cc,Ib0fdcdf4, ... into devel/master X-Git-Tag: dali_2.0.0~6 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=ed11499452da1ccd5fdfa36324881dc66a5281bc;hp=debf82555db7c20b8cb890d0548227ae42ef92d8 Merge changes I2df640e0,Ia1188305,I7fae506e,I7967a7cc,Ib0fdcdf4, ... into devel/master * changes: [AT-SPI] MERGING MARKER [AT-SPI] Correct VISIBLE and SHOWING states [AT-SPI] Windows fixes [AT-SPI] Fixed uint underflow risk [AT-SPI] Guard added for potential null pointer dereference [AT-SPI] Implemented reading popup description [AT-SPI] Improving utc coverage ToggleButton tests [AT-SPI] More coverage [AT-SPI] Improving utc coverage [AT-SPI] Set both ScreenReaderEnabled and IsEnabled in TestEnableSC [AT-SPI] Rewritten UtcDaliControlAccessibilityModal [AT-SPI] Pass correct object to dynamic_cast [AT-SPI] UTC correction [AT-SPI] More UTC fixes [AT-SPI] Execute tct under dbus-launch [AT-SPI] UTC fixes [AT-SPI] Add TestDBusWrapper and bypass compilation problems [AT-SPI] Implement accessibility for Popup [AT-SPI] Fix cmake cmp0004 error [AT-SPI] Catch exception by reference [AT-SPI] Migrate Accessibility tests to dali-toolkit-internal [AT-SPI] Add notification for a11y name/description change [AT-SPI] TextController: emit characters before delete [AT-SPI] EmitStateChanged for togglable PushButton [AT-SPI] Add FOCUSABLE state to TextField and TextEditor [AT-SPI] Add Pause and Resume signals [AT-SPI] Let MarkFilter find the closest mark [AT-SPI] Emit ObjectPropertyChangeEvent::VALUE [AT-SPI] Implement proper accessibility for Slider [AT-SPI] Try auto-scrolling in GrabHighlight [AT-SPI] Override IsScrollable for Scrollable [AT-SPI] Support reading states and tooltips of ToggleButton [AT-SPI] Support gaining keyboard focus in TextField, TextEditor [AT-SPI] Allow two finger pan gesture [AT-SPI] Move setting highlightability property for controls to inheriting classes [AT-SPI] Make Accessible::GetName() fall back to actor name [AT-SPI] Fix role setting [AT-SPI] Squashed implementation --- diff --git a/automated-tests/execute.sh b/automated-tests/execute.sh index 7703340..add0e78 100755 --- a/automated-tests/execute.sh +++ b/automated-tests/execute.sh @@ -118,7 +118,7 @@ else do echo -e "$ASCII_BOLD" echo -e "Executing $mod$ASCII_RESET" - build/src/$mod/tct-$mod-core $opt_serial $opt_noFailedRerun + dbus-launch build/src/$mod/tct-$mod-core $opt_serial $opt_noFailedRerun done summary_end @@ -128,7 +128,7 @@ else summary_start module=$1 shift; - build/src/$module/tct-$module-core $opt_serial $opt_noFailedRerun $* + dbus-launch build/src/$module/tct-$module-core $opt_serial $opt_noFailedRerun $* summary_end else @@ -141,7 +141,7 @@ else if [ $ret -ne 6 ] ; then if [ $opt_debug -ne 0 ] ; then echo DEBUGGING: - gdb --args build/src/$mod/tct-$mod-core $1 + dbus-launch gdb --args build/src/$mod/tct-$mod-core $1 else echo $output diff --git a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt index 4c31f29..7aea8eb 100755 --- a/automated-tests/src/dali-toolkit-internal/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-internal/CMakeLists.txt @@ -8,6 +8,11 @@ SET(CAPI_LIB "dali-toolkit-internal") # List of test case sources (Only these get parsed for test cases) SET(TC_SOURCES utc-Dali-AddOns.cpp + utc-Dali-Accessibility-Accessible.cpp + utc-Dali-Accessibility-Controls.cpp + utc-Dali-Accessibility-Controls-BridgeUp.cpp + utc-Dali-Accessibility-Text.cpp + utc-Dali-Accessibility-Value.cpp utc-Dali-BidirectionalSupport.cpp utc-Dali-ColorConversion.cpp utc-Dali-Control-internal.cpp @@ -39,7 +44,6 @@ SET(TC_SOURCES # Append list of test harness files (Won't get parsed for test cases) LIST(APPEND TC_SOURCES ../dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp - ../dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp @@ -77,14 +81,21 @@ LIST(APPEND TC_SOURCES dali-toolkit-test-utils/toolkit-text-utils.cpp dali-toolkit-test-utils/dummy-visual.cpp dali-toolkit-test-utils/test-addon-manager.cpp + dali-toolkit-test-utils/accessibility-test-utils.cpp + dali-toolkit-test-utils/dbus-wrapper.cpp ) PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED dali2-core dali2-adaptor dali2-toolkit + eldbus + ecore-input + eina ) +MESSAGE("Libraries to link with:>${${CAPI_LIB}_LIBRARIES}") + ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror -DDEBUG_ENABLED -fPIC ) ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} ) @@ -95,6 +106,8 @@ FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS}) SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}") ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS}) +STRING(STRIP ${CMAKE_CXX_LINK_FLAGS} CMAKE_CXX_LINK_FLAGS) + INCLUDE_DIRECTORIES( ../../../ ${${CAPI_LIB}_INCLUDE_DIRS} diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.cpp new file mode 100644 index 0000000..f8eec35 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.cpp @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include "dbus-wrapper.h" + +namespace Dali { + namespace Accessibility { + + using MethodType = TestDBusWrapper::MethodType; + using MessagePtr = DBusWrapper::MessagePtr; + + void TestEnableSC(bool b) { + static bool firstTime = true; + if (b && firstTime) { + firstTime = false; + auto bridge = Accessibility::Bridge::GetCurrentBridge(); + Dali::Stage stage = Dali::Stage::GetCurrent(); + auto accessible = Accessibility::Accessible::Get( stage.GetRootLayer() ); +// bridge->SetApplicationChild( accessible ); // BART + bridge->AddTopLevelWindow( accessible ); // BART + bridge->SetApplicationName( "TestApp" ); + bridge->Initialize(); + + static bool ScreenReaderEnabled = false; + static bool IsEnabled = false; + + auto wr = static_cast(DBusWrapper::Installed()); + + wr->testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr { + auto reply = wr->newReplyMessage(m); + wr->Encode(reply, std::tuple>{ ScreenReaderEnabled }); + return reply; + }; + wr->testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] = [wr](const MessagePtr &m) -> MessagePtr { + auto reply = wr->newReplyMessage(m); + wr->Encode(reply, std::tuple>{ IsEnabled }); + return reply; + }; + wr->testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Bus", "GetAddress", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr { + auto reply = wr->newReplyMessage(m); + wr->Encode(reply, std::tuple{ "bus" }); + return reply; + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible/root", "org.a11y.atspi.Socket", "Embed", MethodType::Method}] = [wr](const MessagePtr &m) -> MessagePtr { + auto reply = wr->newReplyMessage(m); + wr->Encode(reply, std::tuple
{ {"bus", "root"} }); + return reply; + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "PropertyChange", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "StateChanged", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "BoundsChanged", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "ActiveDescendantChanged", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextChanged", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + wr->testMethods[std::tuple{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "TextCaretMoved", MethodType::Method}] = + [wr](const MessagePtr &m) -> MessagePtr { + return wr->newReplyMessage(m); + }; + } + auto wr = static_cast(DBusWrapper::Installed()); + wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", b); + wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "IsEnabled", b); + } + + std::vector
TestGetChildren(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildren", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::string TestGetName(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto name = wr->fromTestGet(adr.GetPath(), "org.a11y.atspi.Accessible", "Name"); + return name; + } + + std::string TestGetDescription(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto description = wr->fromTestGet(adr.GetPath(), "org.a11y.atspi.Accessible", "Description"); + return description; + } + + uint32_t TestGetRole(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRole", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::string TestGetRoleName(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRoleName", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + Address TestGetParent(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestGet< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "Parent"); + return chs; + } + + std::string TestGetLocalizedRoleName(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall(adr.GetPath(), "org.a11y.atspi.Accessible", "GetLocalizedRoleName", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::array< uint32_t, 2 > TestGetStates(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetState", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall>(adr.GetPath(), "org.a11y.atspi.Accessible", "GetAttributes", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Accessible", "DoGesture", + std::tuple< Dali::Accessibility::Gesture, int32_t, int32_t, int32_t, int32_t, Dali::Accessibility::GestureState, uint32_t >(type, xBeg, xEnd, yBeg, yEnd, state, eventTime )); + return std::move(std::get<0>(chs)); + } + + std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetRelationSet", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + Address TestGetChildAtIndex(const Address &adr, int index) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< Address >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetChildAtIndex", std::tuple< int >( index )); + return std::move(std::get<0>(chs)); + } + + ComponentLayer TestGetLayer(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< Dali::Accessibility::ComponentLayer >(adr.GetPath(), "org.a11y.atspi.Component", "GetLayer", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + int TestGetIndexInParent(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< int >(adr.GetPath(), "org.a11y.atspi.Accessible", "GetIndexInParent", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + bool TestGrabFocus(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabFocus", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + bool TestGrabHighlight(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "GrabHighlight", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + bool TestClearHighlight(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Component", "ClearHighlight", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::tuple< int32_t, int32_t, int32_t, int32_t > >(adr.GetPath(), "org.a11y.atspi.Component", "GetExtents", std::tuple(0)); + return std::move(std::get<0>(chs)); + } + + int TestGetMdiZOrder(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< int16_t >(adr.GetPath(), "org.a11y.atspi.Component", "GetMDIZOrder", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + double TestGetAlpha(const Address &adr) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< double >(adr.GetPath(), "org.a11y.atspi.Component", "GetAlpha", std::tuple<>()); + return std::move(std::get<0>(chs)); + } + + std::string TestGetActionName( const Address &adr, size_t index ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetName", std::tuple< int32_t >( index )); + return std::move(std::get<0>(chs)); + } + + std::string TestGetLocalizedActionName( const Address &adr, size_t index ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetLocalizedName", std::tuple< int32_t >( index )); + return std::move(std::get<0>(chs)); + } + + size_t TestGetActionCount( const Address &adr ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto count = wr->fromTestGet< int32_t >(adr.GetPath(), "org.a11y.atspi.Action", "NActions"); + return count; + } + + bool TestDoAction ( const Address &adr, size_t index ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoAction", std::tuple< int32_t >( index )); + return std::move(std::get<0>(chs)); + } + + bool TestDoAction ( const Address &adr, const std::string& name ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< bool >(adr.GetPath(), "org.a11y.atspi.Action", "DoActionName", std::tuple< std::string >( name )); + return std::move(std::get<0>(chs)); + } + + std::string TestGetActionKeyBinding ( const Address &adr, size_t index ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetKeyBinding", std::tuple< int32_t >( index )); + return std::move(std::get<0>(chs)); + } + + std::string TestGetActionDescription ( const Address &adr, size_t index ) + { + auto wr = static_cast(DBusWrapper::Installed()); + auto chs = wr->fromTestCall< std::string >(adr.GetPath(), "org.a11y.atspi.Action", "GetDescription", std::tuple< int32_t >( index )); + return std::move(std::get<0>(chs)); + } + + + void printTree(const Address &root, size_t depth) + { + auto name = TestGetName(root); + printf("%10s", root.GetPath().c_str()); + for(unsigned int i = 0; i < depth; ++i) printf(" "); + printf("%s\n", name.c_str()); + auto chs = TestGetChildren(root); + for(auto &c : chs) + printTree(c, depth + 1); + } + + bool Find( const std::vector< std::string > &collection, const std::string &key) + { + for ( auto& it : collection) + if( it == key ) + return true; + return false; + } + } +} diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h new file mode 100644 index 0000000..8c3d201 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/accessibility-test-utils.h @@ -0,0 +1,43 @@ +#ifndef __DALI_TOOLKIT_ACCESSIBILITY_TEST_UTILS__ +#define __DALI_TOOLKIT_ACCESSIBILITY_TEST_UTILS__ + +#include + + +namespace Dali { + namespace Accessibility { + void TestEnableSC(bool b); + std::vector
TestGetChildren(const Address &adr); + std::string TestGetName(const Address &adr); + std::string TestGetDescription(const Address &adr); + uint32_t TestGetRole(const Address &adr); + std::string TestGetRoleName(const Address &adr); + Address TestGetParent(const Address &adr); + std::string TestGetLocalizedRoleName(const Address &adr); + std::array< uint32_t, 2 > TestGetStates(const Address &adr); + std::unordered_map< std::string, std::string > TestGetAttributes(const Address &adr); + bool TestDoGesture(const Address &adr, Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime); + std::vector< std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > > > TestGetRelationSet(const Address &adr); + Address TestGetChildAtIndex(const Address &adr, int index); + ComponentLayer TestGetLayer(const Address &adr); + int TestGetIndexInParent(const Address &adr); + bool TestGrabFocus(const Address &adr); + bool TestGrabHighlight(const Address &adr); + bool TestClearHighlight(const Address &adr); + std::tuple< int32_t, int32_t, int32_t, int32_t > TestGetExtents(const Address &adr); + int TestGetMdiZOrder(const Address &adr); + double TestGetAlpha(const Address &adr); + void printTree(const Address &root, size_t depth = 0); + bool Find( const std::vector< std::string > &collection, const std::string &key); + std::string TestGetActionName( const Address &adr, size_t index ); + std::string TestGetLocalizedActionName( const Address &adr, size_t index ); + size_t TestGetActionCount( const Address &adr ); + bool TestDoAction ( const Address &adr, size_t index ); + bool TestDoAction ( const Address &adr, const std::string& name ); + std::string TestGetActionKeyBinding ( const Address &adr, size_t index ); + std::string TestGetActionDescription ( const Address &adr, size_t index ); + + } +} + +#endif //__DALI_TOOLKIT_ACCESSIBILITY_TEST_UTILS__ diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.cpp b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.cpp new file mode 100644 index 0000000..d59df19 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.cpp @@ -0,0 +1,1085 @@ +/* + * Copyright 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * 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. + */ + +// CLASS HEADER +#include "dbus-wrapper.h" + +//#include + +// EXTERNAL INCLUDES +#include +#include +#include + +#include +#include + +// INTERNAL INCLUDES +#include + +#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties" + +#undef EINA_FALSE +#undef EINA_TRUE +#define EINA_TRUE static_cast< Eina_Bool >( 1 ) +#define EINA_FALSE static_cast< Eina_Bool >( 0 ) + +//#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0) + +// BART QUICK HACK +#undef assert +#define assert(x) do{}while(0) + +std::atomic< unsigned int > DBus::detail::CallId::LastId{0}; +static std::function< void( const char*, size_t ) > debugPrinter; +static std::mutex debugLock; + +thread_local std::string DBus::DBusServer::currentObjectPath; +thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection; + +void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer ) +{ + std::lock_guard< std::mutex > lock( debugLock ); + debugPrinter = std::move( printer ); +} + +void DBus::debugPrint( const char* file, size_t line, const char* format, ... ) +{ + std::function< void( const char*, size_t ) > debugPrintFunc; + { + std::lock_guard< std::mutex > lock( debugLock ); + if( !debugPrinter ) + return; + debugPrintFunc = debugPrinter; + } + std::vector< char > buf( 4096 ); + int offset; + while( true ) + { + offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) ); + if( offset < 0 ) + return; + if( static_cast< size_t >( offset ) < buf.size() ) + break; + buf.resize( offset + 1 ); + } + + while( true ) + { + va_list args; + va_start( args, format ); + int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args ); + va_end( args ); + if( z < 0 ) + return; + bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size(); + buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) ); + if( done ) + break; + } + debugPrintFunc( buf.data(), buf.size() ); +} + +DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName( const std::string& name ) +{ + return DBUS_W->eldbus_address_connection_get_impl( name ); +} + +DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType( ConnectionType connectionType ) +{ + return DBUS_W->eldbus_connection_get_impl(connectionType); +} + +DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp ) : DBusClient( std::move( busName ), std::move( pathName ), std::move( interfaceName ), getDBusConnectionByType( tp ) ) +{ +} + +DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const DBusWrapper::ConnectionPtr &conn ) +{ + if( !conn ) + connectionState->connection = getDBusConnectionByType( ConnectionType::SESSION ); + else + connectionState->connection = conn; + + std::ostringstream o; + o << "bus = " << busName << " path = " << pathName << " connection = " << DBUS_W->eldbus_connection_unique_name_get_impl( connectionState->connection ); + info = o.str(); + + connectionState->object = DBUS_W->eldbus_object_get_impl( connectionState->connection, busName.c_str(), pathName.c_str() ); + if( connectionState->object ) + { + connectionState->proxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, interfaceName ); + if( interfaceName != DBUS_INTERFACE_PROPERTIES ) + { + connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, DBUS_INTERFACE_PROPERTIES ); + } + else + { + connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl( connectionState->proxy ); + } + } + connectionInfo = std::make_shared< ConnectionInfo >(); + connectionInfo->busName = std::move( busName ); + connectionInfo->pathName = std::move( pathName ); + connectionInfo->interfaceName = std::move( interfaceName ); +} + +DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) ) +{ +} + +DBus::DBusServer::DBusServer( const DBusWrapper::ConnectionPtr &conn ) +{ + if( !conn ) + connection = getDBusConnectionByType( ConnectionType::SESSION ); + else + connection = conn; +} + +DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) ) +{ +} + +void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback ) +{ + DBUS_W->add_interface_impl( fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals ); +} + +std::string DBus::DBusServer::getBusName() const +{ + return getConnectionName( connection ); +} + +std::string DBus::getConnectionName( const DBusWrapper::ConnectionPtr &c ) +{ + return DBUS_W->eldbus_connection_unique_name_get_impl( c ); +} + +bool DBus::DBusClient::getFromEinaValue(const _Eina_Value *v, void *dst) +{ + return eina_value_get(const_cast(v), dst); +} + +/// \cond +static std::unique_ptr InstalledWrapper; + +struct DefaultDBusWrapper : public DBusWrapper { + constexpr static int ELDBUS_CALL_TIMEOUT = 1000; + + DefaultDBusWrapper() { + } + ~DefaultDBusWrapper() { + } + #define DEFINE_GS(name, eldbus_name, unref_call) \ + static eldbus_name *get(const std::shared_ptr &a) { \ + return static_cast(a.get())->Value; \ + } \ + static eldbus_name *release(const std::shared_ptr &a) { \ + auto z = static_cast(a.get())->Value; \ + static_cast(a.get())->Value = nullptr; \ + return z; \ + } \ + template static std::shared_ptr create(const eldbus_name *v, ARGS && ... args) { \ + return std::make_shared(const_cast(v), std::forward(args)...); \ + } + + #define DEFINE_TYPE(name, eldbus_name, unref_call) \ + struct name ## Impl : public name { \ + eldbus_name *Value = nullptr; \ + bool EraseOnExit = false; \ + name ## Impl(eldbus_name *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { } \ + ~name ## Impl() { \ + if (EraseOnExit && Value) { unref_call; } \ + } \ + }; \ + DEFINE_GS(name, eldbus_name, unref_call) + + struct ConnectionImpl : public Connection { + Eldbus_Connection *Value = nullptr; + bool EraseOnExit = false; + ConnectionImpl(Eldbus_Connection *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { + ecore_event_init(); + eldbus_init(); + } + ~ConnectionImpl() { + if (EraseOnExit && Value) { + eldbus_connection_unref( Value ); + } + eldbus_shutdown(); + ecore_event_shutdown(); + } + }; + struct MessageIterImpl : public MessageIter { + Eldbus_Message_Iter *Value = nullptr, *Parent = nullptr; + bool EraseOnExit = false; + MessageIterImpl(Eldbus_Message_Iter *Value, Eldbus_Message_Iter *Parent, bool EraseOnExit = false) : Value(Value), Parent(Parent), EraseOnExit(EraseOnExit) { } + ~MessageIterImpl() { + if (EraseOnExit && Value && Parent) + eldbus_message_iter_container_close(Parent, Value); + } + }; + + DEFINE_GS(Connection, Eldbus_Connection, ) + DEFINE_GS(MessageIter, Eldbus_Message_Iter, ) + DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value )) + DEFINE_TYPE(Proxy, Eldbus_Proxy, ) + DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value )) + DEFINE_TYPE(Pending, Eldbus_Pending, ) + DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, ) + #undef DEFINE_TYPE + + std::shared_ptr eldbus_address_connection_get_impl(const std::string &addr) override { + eldbus_init(); + auto p = eldbus_address_connection_get(addr.c_str()); + auto w = create(p, true); + eldbus_shutdown(); + return w; + } + +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type src) override { \ + eldbus_message_iter_arguments_append( get(it), #sig, src ); \ + } \ + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type &dst) override { \ + return eldbus_message_iter_get_and_next( get(it), (#sig)[0], &dst ); \ + } + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + +#undef eldbus_message_iter_arguments_append_impl_basic + + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, bool src) override { + eldbus_message_iter_arguments_append( get(it), "b", src ? 1 : 0 ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, bool &dst) override { + unsigned char q; + auto z = eldbus_message_iter_get_and_next( get(it), 'b', &q ); + dst = q != 0; + return z; + } + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const std::string &src) override { + eldbus_message_iter_arguments_append( get(it), "s", src.c_str() ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, std::string &dst) override { + auto iter = get(it); + const char* q; + if( !eldbus_message_iter_get_and_next( iter, 's', &q ) ) + { + if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) ) + return false; + } + dst = q; + return true; + } + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const ObjectPath &src) override { + eldbus_message_iter_arguments_append( get(it), "o", src.value.c_str() ); + } + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, ObjectPath &dst) override { + const char* q; + if( !eldbus_message_iter_get_and_next( get(it), 'o', &q ) ) + return false; + dst.value = q; + return true; + } + + MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override { + auto z = eldbus_message_iter_container_new( get(it), type, !sig.empty() ? sig.c_str() : NULL ); + return create(z, get(it), true); + } + MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override { + Eldbus_Message_Iter* entry; + if (!eldbus_message_iter_get_and_next( get(it), type, &entry ) ) return {}; + return create(entry, get(it), false); + } + MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &msg, bool) override { + return create(eldbus_message_iter_get(get(msg)), nullptr, false); + } + MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) { + return create(eldbus_proxy_method_call_new( get(proxy), funcName.c_str() ) ); + } + MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override { + return create(eldbus_proxy_send_and_block(get(proxy), release(msg), ELDBUS_CALL_TIMEOUT) ); + } + bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override { + const char *errname, *errmsg; + if( eldbus_message_error_get( get(msg), &errname, &errmsg ) ) { + name = errname; + text = errmsg; + return true; + } + return false; + } + std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override { + return eldbus_message_signature_get(get(msg)); + } + + static void callAsyncCb( void* data, const Eldbus_Message *msg, Eldbus_Pending *pending ) + { + auto d = static_cast< SendCallback* >( data ); + (*d)( create(msg, false) ); + } + static void pendingFreeCb( void* data, const void* ) + { + auto d = static_cast< SendCallback* >( data ); + delete d; + } + static void listenerCallbackFree( void* data, const void* ) + { + auto d = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data ); + delete d; + } + + PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override { + auto cb = new SendCallback{ callback }; + auto pending = eldbus_proxy_send( get(proxy), release(msg), callAsyncCb, cb, ELDBUS_CALL_TIMEOUT ); + if( pending ) + { + eldbus_pending_free_cb_add( pending, pendingFreeCb, cb ); + } + else + { + delete cb; + } + return create(pending, false); + } + std::string eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) override { + return eldbus_proxy_interface_get( get(proxy) ); + } + static void listenerCallback( void* data, const Eldbus_Message* msg ) + { + auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data ); + ( *p )( msg ); + } + void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) override { + auto tmp = new std::function< void( const Eldbus_Message* msg ) >{ + [cb](const Eldbus_Message* msg) { + cb(create(msg, false)); + } + }; + auto handler = eldbus_proxy_signal_handler_add( get(proxy), member.c_str(), listenerCallback, tmp ); + if( handler ) + eldbus_proxy_free_cb_add( get(proxy), listenerCallbackFree, tmp ); + else + delete tmp; + } + std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override { + return eldbus_message_iter_signature_get( get(iter) ); + } + MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override { + return create(eldbus_message_method_return_new( get(msg) ) ); + } + MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override { + return create(eldbus_message_error_new( get(msg), err.c_str(), txt.c_str() ) ); + } + PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override { + return create(eldbus_connection_send( get(conn), get(msg), NULL, NULL, -1 ) ); + } + MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override { + return create(eldbus_message_signal_new( path.c_str(), iface.c_str(), name.c_str() ) ); + } + MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override { + return create(eldbus_message_ref( get(msg) ), true ); + } + ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override { + Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM; + + switch( type ) + { + case ConnectionType::SYSTEM: + { + eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM; + break; + } + case ConnectionType::SESSION: + { + eldbusType = ELDBUS_CONNECTION_TYPE_SESSION; + break; + } + } + + eldbus_init(); + auto p = eldbus_connection_get( eldbusType ); + auto w = create(p, true); + eldbus_shutdown(); + return w; + } + std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override { + return eldbus_connection_unique_name_get( get(conn) ); + } + ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override { + return create(eldbus_object_get(get(conn), bus.c_str(), path.c_str() ), true ); + } + ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override { + return create(eldbus_proxy_get(get(obj), interface.c_str() ), false ); + } + ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override { + return create(get(ptr), false ); + } + + + + + + + struct Implementation + { + Eldbus_Service_Interface_Desc dsc; + std::vector< std::vector< Eldbus_Arg_Info > > argsInfos; + std::vector< Eldbus_Method > methods; + std::vector< Eldbus_Signal > signals; + std::vector< Eldbus_Property > properties; + + std::unordered_map< std::string, DBusWrapper::MethodInfo > methodsMap; + std::unordered_map< std::string, DBusWrapper::PropertyInfo > propertiesMap; + std::unordered_map< unsigned int, DBusWrapper::SignalInfo > signalsMap; + + DBusWrapper::ConnectionWeakPtr connection; + }; + + static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries; + static std::mutex globalEntriesMutex; + +#undef EINA_FALSE +#undef EINA_TRUE +#define EINA_FALSE static_cast(0) +#define EINA_TRUE static_cast(1) + + static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, + const Eldbus_Message* message, Eldbus_Message** error ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + return EINA_FALSE; + + auto it = impl->propertiesMap.find( propertyName ); + if( it == impl->propertiesMap.end() || !it->second.getCallback ) + return EINA_FALSE; + + auto connection = impl->connection.lock(); + if( !connection ) + return EINA_FALSE; + + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.getCallback( create(message, false), create(iter, nullptr, false) ); + if( !reply.empty() ) + { + if( error ) + *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() ); + return EINA_FALSE; + } + + return EINA_TRUE; + } + + static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter, + const Eldbus_Message* message ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" ); + return ret; + } + auto it = impl->propertiesMap.find( propertyName ); + if( it == impl->propertiesMap.end() || !it->second.setCallback ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" ); + return ret; + } + auto connection = impl->connection.lock(); + if( !connection ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" ); + return ret; + } + + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.setCallback( create(message, false), create(iter, nullptr, false) ); + + Eldbus_Message* ret = nullptr; + if( !reply.empty() ) + { + ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() ); + } + else + { + ret = eldbus_message_method_return_new( message ); + } + return ret; + } + + static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message ) + { + Implementation* impl = nullptr; + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto it = globalEntries.find( iface ); + if( it != globalEntries.end() ) + impl = it->second.get(); + } + if( !impl ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" ); + return ret; + } + std::string memberName = eldbus_message_member_get( message ); + auto it = impl->methodsMap.find( memberName ); + if( it == impl->methodsMap.end() ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" ); + return ret; + } + auto connection = impl->connection.lock(); + if( !connection ) + { + auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" ); + return ret; + } + DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) ); + auto reply = it->second.callback( create(message) ); + return release(reply); + } + + void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) override + { + std::vector< Eldbus_Method > methods; + std::vector< Eldbus_Signal > signals; + std::vector< Eldbus_Property > properties; + std::vector< std::vector< Eldbus_Arg_Info > > argsInfos; + std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap; + std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap; + std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap; + + DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() ); + auto makeArgInfo = [&](const std::vector> &input) { + argsInfos.push_back({}); + auto &dst = argsInfos.back(); + for(auto &s : input) { + auto a = Strings.add(s.first); + auto b = Strings.add(s.second); + dst.push_back({ a, b }); + } + dst.push_back({ nullptr, nullptr }); + return dst.data(); + }; + for( auto& ee : dscrMethods ) + { + auto key = ee.memberName; + DBUS_DEBUG( "adding method %s", ee.memberName.c_str() ); + for( auto& r : ee.in ) + { + DBUS_DEBUG( "in %s '%s'", r.first.c_str(), r.second.c_str() ); + } + for( auto& r : ee.out ) + { + DBUS_DEBUG( "out %s '%s'", r.first.c_str(), r.second.c_str() ); + } + auto& e = ( methodsMap[key] = std::move( ee ) ); + methods.push_back( {} ); + auto& m = methods.back(); + m.member = e.memberName.c_str(); + m.in = makeArgInfo(e.in); + m.out = makeArgInfo(e.out); + m.cb = method_callback; + m.flags = 0; + } + for( auto& ee : dscrProperties ) + { + auto key = ee.memberName; + DBUS_DEBUG( "adding property %s", ee.memberName.c_str() ); + auto& e = ( propertiesMap[key] = std::move( ee ) ); + properties.push_back( {} ); + auto& m = properties.back(); + m.name = e.memberName.c_str(); + m.type = e.typeSignature.c_str(); + m.get_func = e.getCallback ? property_get_callback : nullptr; + m.set_func = e.setCallback ? property_set_callback : nullptr; + m.flags = 0; + } + dscrMethods.clear(); + dscrProperties.clear(); + dscrSignals.clear(); + + methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} ); + signals.push_back( {nullptr, nullptr, 0} ); + properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} ); + + auto impl = std::unique_ptr< Implementation >( new Implementation{ + {interfaceName.c_str(), + methods.data(), + signals.data(), + properties.data(), + nullptr, + nullptr}, + std::move( argsInfos ), + std::move( methods ), + std::move( signals ), + std::move( properties ), + std::move( methodsMap ), + std::move( propertiesMap ), + std::move( signalsMap ), + connection} ); + + { + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + auto v = fallback ? eldbus_service_interface_fallback_register( get(connection), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( get(connection), pathName.c_str(), &impl->dsc ); + assert( v ); + globalEntries[v] = std::move( impl ); + DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 ); + destructors.push_back([=]() { + DBUS_DEBUG( "unregistering interface %p", v ); + eldbus_service_interface_unregister( v ); + std::lock_guard< std::mutex > lock( globalEntriesMutex ); + globalEntries.erase( v ); + }); + } + } + static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event ) + { + auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data ); + ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) ); + } + static void ProxyEventCallbackDelCb( void* data, const void *obj ) + { + auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data ); + delete d; + } + void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) override { + auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed *epc ) >{ + [cb, name, interface]( Eldbus_Proxy_Event_Property_Changed *ev ) { + const char* ifc = eldbus_proxy_interface_get( ev->proxy ); + if( ev->name && ev->name == name && ifc && interface == ifc ) + { + cb(ev->value); + } + } }; + auto p = get(proxy); + eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, + listenerEventChangedCallback, callbackLambdaPtr ); + eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr ); + } +}; + +std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries; +std::mutex DefaultDBusWrapper::globalEntriesMutex; + +DBusWrapper *DBusWrapper::Installed() +{ + if (!InstalledWrapper) + InstalledWrapper.reset(new DefaultDBusWrapper); + return InstalledWrapper.get(); +} + +void DBusWrapper::Install(std::unique_ptr w) +{ + InstalledWrapper = std::move(w); +} + + +struct TestDBusWrapper::ConnectionImpl : public TestDBusWrapper::Connection { +}; + +TestDBusWrapper::TestDBusWrapper() +{ + eina_init(); + connection = std::make_shared(); + testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", MethodType::Getter}] = + testMethods[std::tuple{"/org/a11y/bus", "org.a11y.Status", "IsEnabled", MethodType::Getter}] = + [this](const DBusWrapper::MessagePtr &m) -> MessagePtr { + auto reply = newReplyMessage(m); + Encode(reply, std::tuple>{ TestDBusWrapper::Variant{ false} }); + return reply; + }; +} +TestDBusWrapper::~TestDBusWrapper() +{ + eina_shutdown(); +} + +TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_address_connection_get_impl(const std::string &addr) +{ + return connection; +} + +struct TestDBusWrapper::MessageIterImpl : public TestDBusWrapper::MessageIter { + MessagePtr msg; + Element *elem; + bool write; + std::list::iterator it; + MessageIterImpl(MessagePtr msg, Element *elem, bool write) : msg(std::move(msg)), elem(elem), write(write) { + if (!write) it = elem->get().begin(); + } + MessageIterImpl(MessagePtr msg, Element *elem, bool write, std::list::iterator it) : msg(std::move(msg)), elem(elem), write(write), it(it) { } +}; + +struct TestDBusWrapper::MessageImpl : public TestDBusWrapper::Message { + std::string bus, path, interface, name; + Element data; + bool reply, error = false; + std::string error_a, error_b; + + MessageImpl(std::string bus, std::string path, std::string interface, std::string name, bool reply) : + bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, reply(reply) { } + MessageImpl(std::string bus, std::string path, std::string interface, std::string name, std::string error_a, std::string error_b) : + bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)), name(std::move(name)), data{ ElementList{} }, + reply(true), error(true), error_a(std::move(error_a)), error_b(std::move(error_b)) { } +}; + +struct TestDBusWrapper::ProxyImpl : public TestDBusWrapper::Proxy { + std::string bus, path, interface; + ProxyImpl(std::string bus, std::string path, std::string interface) : bus(std::move(bus)), path(std::move(path)), interface(std::move(interface)) { } +}; +struct TestDBusWrapper::ObjectImpl : public TestDBusWrapper::Object { + std::string bus, path; + ObjectImpl(std::string bus, std::string path) : bus(std::move(bus)), path(std::move(path)) { } +}; +#define DEFINE_TYPE(name) TestDBusWrapper::name ## Impl *TestDBusWrapper::get(const name ## Ptr &v) { return static_cast(v.get()); } + DEFINE_TYPE(Connection) + DEFINE_TYPE(Proxy) + DEFINE_TYPE(Object) + DEFINE_TYPE(Message) + DEFINE_TYPE(MessageIter) +#undef DEFINE_TYPE + +template void TestDBusWrapperAppendBasic(const TestDBusWrapper::MessageIterPtr &it, T src) { + auto m = TestDBusWrapper::get(it); + if (!m->write) throw TestDBusWrapper::error{}; + if (!m->elem->isContainer()) throw TestDBusWrapper::error{}; + m->elem->get().push_back(TestDBusWrapper::Element{ src }); +} +template bool TestDBusWrapperGetBasicAndNext(const TestDBusWrapper::MessageIterPtr &it, T &src) { + auto m = TestDBusWrapper::get(it); + if (m->write) throw TestDBusWrapper::error{}; + if (!m->elem->isContainer()) return false; + auto &lst = m->elem->get(); + if (m->it == lst.end()) return false; + if (!m->it->is()) return false; + src = m->it->get(); + ++m->it; + return true; +} + +#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ +void TestDBusWrapper::eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) { \ + TestDBusWrapperAppendBasic(it, src); \ +} \ +bool TestDBusWrapper::eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) { \ + return TestDBusWrapperGetBasicAndNext(it, dst); \ +} +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ +eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + +eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) +eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) +eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) +eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) +eldbus_message_iter_arguments_append_impl_basic(int16_t, n) +eldbus_message_iter_arguments_append_impl_basic(int32_t, i) +eldbus_message_iter_arguments_append_impl_basic(int64_t, x) +eldbus_message_iter_arguments_append_impl_basic(double, d) +eldbus_message_iter_arguments_append_impl_basic(bool, b) +eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) +eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +#undef eldbus_message_iter_arguments_append_impl_basic +#undef eldbus_message_iter_arguments_append_impl_basic_impl + +TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) { + auto m = get(it); + if (!m->write) throw error{}; + if (!m->elem->isContainer()) throw error{}; + auto &lst = m->elem->get(); + if (type == 'r' || type == 'e' || type == 'a' || type == 'v') { + lst.push_back({ ElementList{}, type }); + return std::make_shared(MessageIterImpl{ m->msg, &lst.back(), true }); + } + throw error{}; +} + +TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) { + auto m = get(it); + if (m->write) throw error{}; + if (!m->elem->isContainer()) throw error{} << "not a container"; + auto &lst = m->elem->get(); + if (m->it == lst.end()) return {}; + if (m->it->signature() != type) return {}; + auto v = std::make_shared(MessageIterImpl{ m->msg, &*m->it, false }); + ++m->it; + return v; +} + +TestDBusWrapper::MessageIterPtr TestDBusWrapper::eldbus_message_iter_get_impl(const MessagePtr &it, bool write) { + auto m = get(it); + return std::make_shared(MessageIterImpl{ it, &m->data, write, m->data.get().begin() }); +} + +bool TestDBusWrapper::completed(const MessageIterPtr &iter) +{ + auto m = get(iter); + assert(!m->write); + return m->it == m->elem->get().end(); +} + +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) { + auto p = get(proxy); + return std::make_shared(MessageImpl{ + p->bus, p->path, p->interface, funcName, false + }); +} +TestDBusWrapper::MessagePtr TestDBusWrapper::call( + std::unordered_map, std::function> &mp, + const std::string &mpName, const MessagePtr &msg, MethodType type) { + auto m = get(msg); + auto findMethod = [&](std::string path, const std::string &iname, const std::string &name, MethodType type) { + if (path.empty()) throw error{}; + if (path[0] != '/') { + path = "/org/a11y/atspi/accessible/" + path; + m->path = path; + } + while(!path.empty()) { + auto it = mp.find(std::tuple { path, iname, name, type }); + if (it != mp.end()) return it; + auto index = path.rfind('/'); + if (index == std::string::npos) break; + path.resize(index); + } + return mp.end(); + }; + std::string iname, name; + if (type == MethodType::Method && m->interface == "org.freedesktop.DBus.Properties") { + type = m->name == "Get" ? MethodType::Getter : MethodType::Setter; + auto &lst = m->data.get(); + assert(lst.size() >= 2); + iname = lst.front().get(); + lst.pop_front(); + name = lst.front().get(); + lst.pop_front(); + } + else { + iname = m->interface; + name = m->name; + } + auto it = findMethod(m->path, iname, name, type); + if (it == mp.end()) { + const char *mt; + if (type == MethodType::Method) mt = "MethodType::Method"; + else if (type == MethodType::Getter) mt = "MethodType::Getter"; + else if (type == MethodType::Setter) mt = "MethodType::Setter"; + else assert(0); + throw error{} << "missing {\"" << m->path << "\", \"" << iname << "\", \"" << name << "\", " << mt << "} in " << mpName; + } + DBus::DBusServer::CurrentObjectSetter setter{ connection, m->path }; + return it->second(msg); +} +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) { +// BART +// auto p = get(proxy); +// auto m = get(msg); +// assert(p->bus == m->bus); +// assert(p->path == m->path); +// assert(p->interface == m->interface); + return call(testMethods, "testMethods", msg, MethodType::Method); +} + +bool TestDBusWrapper::eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) { + auto m = get(msg); + name = m->error_a; + text = m->error_b; + return m->error; +} +static void calculate_signature(std::ostringstream &ostr, TestDBusWrapper::Element &e) +{ + ostr << static_cast(e.signature()); + if (e.isContainer()) { + ostr << "("; + auto &lst = e.get(); + for(auto &q : lst) calculate_signature(ostr, q); + ostr << ")"; + } +} +std::string TestDBusWrapper::eldbus_message_signature_get_impl(const MessagePtr &msg) { + auto m = get(msg); + std::ostringstream ostr; + for(auto &q : m->data.get()) + calculate_signature(ostr, q); + return ostr.str(); +} +TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) { +// BART +// auto p = get(proxy); +// auto m = get(msg); +// assert(p->bus == m->bus); +// assert(p->path == m->path); +// assert(p->interface == m->interface); + asyncCalls.push_back([this, msg, callback]() { + auto r = call(testMethods, "testMethods", msg, MethodType::Method); + callback(r); + }); + return {}; +} +std::string TestDBusWrapper::eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) { + auto p = get(proxy); + return p->interface; +} +void TestDBusWrapper::eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) { + auto p = get(proxy); + daliSignals[std::tuple { p->path, p->interface, member }] = cb; +} +std::string TestDBusWrapper::eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) { + auto m = get(iter); + if (m->write) throw error{}; + if (!m->elem->isContainer()) throw error{}; + std::ostringstream ostr; + auto &lst = m->elem->get(); + for(auto it = m->it; it != lst.end(); ++it) + calculate_signature(ostr, *it); + return ostr.str(); +} +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_method_return_new_impl( const MessagePtr &msg) { + auto m = get(msg); + return std::make_shared(MessageImpl{ + m->bus, m->path, m->interface, m->name, true + }); +} +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) { + auto m = get(msg); + return std::make_shared(MessageImpl{ + m->bus, m->path, m->interface, m->name, err, txt + }); +} +TestDBusWrapper::PendingPtr TestDBusWrapper::eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) { + call(testMethods, "testMethods", msg, MethodType::Method); + return {}; +} +std::shared_ptr TestDBusWrapper::createEinaValue(bool b) { + Eina_Value *value = eina_value_new(EINA_VALUE_TYPE_UCHAR); + eina_value_set(value, b); + return std::shared_ptr(value, [](Eina_Value *v) { + eina_value_free(v); + }); +} + +TestDBusWrapper::MessagePtr TestDBusWrapper::newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply) { + return std::make_shared(MessageImpl{ + "bus", path, interface, name, reply + }); +} + +TestDBusWrapper::MessagePtr TestDBusWrapper::newReplyMessage(const MessagePtr &msg) { + auto m = get(msg); + return newMessage(m->path, m->interface, m->name, true); +} + +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) { + return std::make_shared(MessageImpl{ + "bus", path, iface, name, true + }); +} +TestDBusWrapper::MessagePtr TestDBusWrapper::eldbus_message_ref_impl(const MessagePtr &msg) { + return msg; +} +TestDBusWrapper::ConnectionPtr TestDBusWrapper::eldbus_connection_get_impl(ConnectionType type) { + return connection; +} +std::string TestDBusWrapper::eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) { + return "bus"; +} +TestDBusWrapper::ObjectPtr TestDBusWrapper::eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) { + return std::make_shared(ObjectImpl{ + bus, path + }); +} +TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) { + auto o = get(obj); + return std::make_shared(ProxyImpl{ o->bus, o->path, interface }); +} +TestDBusWrapper::ProxyPtr TestDBusWrapper::eldbus_proxy_copy_impl( const ProxyPtr &ptr) { + return ptr; +} +void TestDBusWrapper::add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) { + auto p = get(proxy); + propertyChangeListeners[std::tuple{ p->path, interface, name }] = cb; +} +void TestDBusWrapper::add_interface_impl( bool fallback, const std::string& path_, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interface, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) { + std::string bus = "bus"; + std::string path = path_; + while(!path.empty() && path.back() == '/') path.pop_back(); + for(auto &m : dscrMethods) { + auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Method ); + daliMethods[key] = m.callback; + } + for(auto &m : dscrProperties) { + auto key = std::make_tuple( "/org/a11y/atspi/accessible" + path, interface, m.memberName, MethodType::Getter ); + daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr { + auto ret = std::make_shared(MessageImpl{ + "bus", path, interface, m.memberName, true + }); + auto v = m.getCallback(msg, std::make_shared(MessageIterImpl{ ret, &ret->data, true })); + ret->error = !v.empty(); + if (ret->error) { + ret->error_a = "call failed"; + ret->error_b = std::move(v); + } + return ret; + }; + std::get<3>(key) = MethodType::Setter; + daliMethods[key] = [=](const MessagePtr &msg) -> MessagePtr { + auto v = m.setCallback(msg, std::make_shared(MessageIterImpl{ msg, &get(msg)->data, false })); + return v.empty() ? std::make_shared(MessageImpl{ + "bus", path, interface, m.memberName, true, + }) : std::make_shared(MessageImpl{ + "bus", path, interface, m.memberName, "call failed", v + }); + // interface is probably wrong, due to retarded way properties are handlded by dbus + }; + } + for(auto &m : dscrSignals) { + daliSignalsMap[std::tuple{ "/org/a11y/atspi/accessible" + path, interface, m.uniqueId }] = m.memberName; + } +} + +/// \endcond diff --git a/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h new file mode 100644 index 0000000..e44aa56 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/dbus-wrapper.h @@ -0,0 +1,3330 @@ +#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H +#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H + +/* + * Copyright 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + + * 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. + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +//#include +//#include + +#include + +#define ATSPI_PREFIX_PATH "/org/a11y/atspi/accessible/" +#define ATSPI_NULL_PATH "/org/a11y/atspi/null" + + +//// BART QUICK HACK +#define bart_assert(x) do{}while(0) + +struct _Eina_Value; + +/// \cond +struct ObjectPath +{ + std::string value; +}; + +struct DBusWrapper +{ + virtual ~DBusWrapper() = default; + + enum class ConnectionType + { + SYSTEM, + SESSION + }; + +#define DEFINE_TYPE(name, eldbus_name, unref_call) \ + struct name { virtual ~name() = default; }; \ + using name ## Ptr = std::shared_ptr; \ + using name ## WeakPtr = std::weak_ptr; \ + + DEFINE_TYPE(Connection, Eldbus_Connection, ) + DEFINE_TYPE(MessageIter, Eldbus_Message_Iter, eldbus_message_iter_container_close( Value )) + DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value )) + DEFINE_TYPE(Proxy, Eldbus_Proxy, eldbus_proxy_unref( Value )) + DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value )) + DEFINE_TYPE(Pending, Eldbus_Pending, ) + DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, ) + +#undef DEFINE_TYPE + virtual ConnectionPtr eldbus_address_connection_get_impl(const std::string &addr) = 0; + +#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ + virtual void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) = 0; \ + virtual bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) = 0; +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + eldbus_message_iter_arguments_append_impl_basic(bool, b) + eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) + eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +#undef eldbus_message_iter_arguments_append_impl_basic +#undef eldbus_message_iter_arguments_append_impl_basic_impl + + virtual MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) = 0; + virtual MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) = 0; + virtual MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &it, bool write) = 0; + virtual MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) = 0; + virtual MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) = 0; + virtual bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) = 0; + virtual std::string eldbus_message_signature_get_impl(const MessagePtr &msg) = 0; + + using SendCallback = std::function; + virtual PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) = 0; + virtual std::string eldbus_proxy_interface_get_impl(const ProxyPtr &) = 0; + virtual void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) = 0; + virtual std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) = 0; + virtual MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) = 0; + virtual MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) = 0; + virtual PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) = 0; + virtual MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) = 0; + virtual MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) = 0; + virtual ConnectionPtr eldbus_connection_get_impl(ConnectionType type) = 0; + virtual std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) = 0; + virtual ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) = 0; + virtual ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) = 0; + virtual ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) = 0; + + class StringStorage + { + public: + struct char_ptr_deleter + { + void operator()( char* p ) + { + free( p ); + } + }; + std::vector< std::unique_ptr< char, char_ptr_deleter > > storage; + + const char* add( const char* txt ) + { + auto ptr = strdup( txt ); + storage.push_back( std::unique_ptr< char, char_ptr_deleter >( ptr ) ); + return storage.back().get(); + } + const char* add( const std::string& txt ) + { + return add( txt.c_str() ); + } + }; + + struct CallId + { + static std::atomic< unsigned int > LastId; + unsigned int id = ++LastId; + }; + struct MethodInfo + { + CallId id; + std::string memberName; + std::vector< std::pair > in, out; // _Eldbus_Arg_Info + std::function< DBusWrapper::MessagePtr( const DBusWrapper::MessagePtr &msg ) > callback; + }; + struct SignalInfo + { + CallId id; + std::string memberName; + std::vector< std::pair > args; + unsigned int uniqueId; + }; + struct PropertyInfo + { + CallId setterId, getterId; + std::string memberName, typeSignature; + std::function< std::string( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &dst ) > getCallback, setCallback; + }; + struct SignalId + { + CallId id; + + SignalId() = default; + SignalId( CallId id ) : id( id ) {} + }; + virtual void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) = 0; + virtual void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const _Eina_Value * ) > cb) = 0; + static DBusWrapper *Installed(); + static void Install(std::unique_ptr); + + StringStorage Strings; +}; + +namespace detail { + enum class MethodType { + Method, Getter, Setter + }; +} + +namespace std { + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::hash()(std::get<2>(a)); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + return v; + } + }; + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::hash()(std::get<2>(a)); + auto a4 = static_cast(std::get<3>(a)); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + v = (v * 11400714819323198485llu) + a4; + return v; + } + }; + template <> struct hash> { + size_t operator () (const std::tuple &a) const { + auto a1 = std::hash()(std::get<0>(a)); + auto a2 = std::hash()(std::get<1>(a)); + auto a3 = std::get<2>(a); + size_t v = a1; + v = (v * 11400714819323198485llu) + a2; + v = (v * 11400714819323198485llu) + a3; + return v; + } + }; +} +namespace detail { + template struct DBusSigImpl { enum { value = 0, end = 0 }; }; + template struct DBusSig { enum { value = DBusSigImpl::type>::value, end = DBusSigImpl::type>::end }; }; + template struct IndexFromTypeTupleImpl { + enum { value = std::is_same::type>::type, Q>::value ? I : IndexFromTypeTupleImpl::value }; + }; + template struct IndexFromTypeTupleImpl { enum { value = S }; }; + template struct IndexFromTypeTuple { + enum { value = IndexFromTypeTupleImpl::type, 0, std::tuple_size::value>::value }; + }; + template struct Encoder; + template struct EncoderTuple; +} +struct TestDBusWrapper : public DBusWrapper +{ + using MethodType = detail::MethodType; + ConnectionPtr connection; + std::unordered_map, std::function> testMethods; + std::unordered_map, std::function> daliMethods; + std::unordered_map, std::string> daliSignalsMap; + std::unordered_map, std::function> daliSignals; + std::unordered_map, std::function> propertyChangeListeners; + + std::vector> asyncCalls; + + template struct Variant { + T value; + Variant() = default; + Variant(T t) : value(std::move(t)) { } + }; + template void Encode(const MessagePtr &m, const std::tuple &args) { + auto iter = eldbus_message_iter_get_impl(m, true); + detail::EncoderTuple<0, sizeof...(ARGS), ARGS...>::encode(*this, iter, args); + } + template void Decode(const MessagePtr &m, std::tuple &args) { + auto iter = eldbus_message_iter_get_impl(m, false); + detail::EncoderTuple<0, sizeof...(ARGS), ARGS...>::decode(*this, args, iter); + } + MessagePtr newMessage(const std::string &path, const std::string &interface, const std::string &name, bool reply); + MessagePtr newReplyMessage(const MessagePtr &m); + + template void fromTestEmitSignal(std::string path, const std::string &interface, const std::string &name, const std::tuple &args) { + if (path.empty()) throw error{}; + if (path[0] != '/') path = "/org/a11y/atspi/accessible/" + path; + auto msg = newMessage(path, interface, name, false); + Encode(msg, args); + auto it = daliSignals.find(std::tuple{ path, interface, name }); + if (it == daliSignals.end()) throw error{}; + it->second(msg); + } + static std::shared_ptr<_Eina_Value> createEinaValue(bool); + template void fromTestChangeProperty(std::string path, const std::string &interface, const std::string &name, T new_value) { + auto v = createEinaValue(new_value); + if (path.empty()) throw error{}; + if (path[0] != '/') path = "/org/a11y/atspi/accessible/" + path; + auto it = propertyChangeListeners.find(std::tuple{ path, interface, name }); + if (it == propertyChangeListeners.end()) throw error{}; + it->second(v.get()); + } + template std::tuple fromTestCall(const std::string &path, const std::string &interface, const std::string &name, const std::tuple &args) { + auto msg = newMessage(path, interface, name, false); + Encode(msg, args); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Method); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return tmp; + } + template T fromTestGet(const std::string &path, const std::string &interface, const std::string &name) { + auto msg = newMessage(path, interface, name, false); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Getter); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return std::move(std::get<0>(tmp)); + } + template std::tuple fromTestSet(const std::string &path, const std::string &interface, const std::string &name, const T &arg) { + auto msg = newMessage(path, interface, name, false); + Encode(msg, TestDBusWrapper::Variant{ arg }); + auto res = call(daliMethods, "daliMethods", msg, MethodType::Setter); + std::string a, b; + if (eldbus_message_error_get_impl(res, a, b)) throw error{} << "call to " << path << " " << interface << " " << name << " failed: " << a << ": " << b; + std::tuple tmp; + Decode(res, tmp); + return tmp; + } + + TestDBusWrapper(); + ~TestDBusWrapper(); + + class error : public std::exception { + std::shared_ptr temp = std::make_shared(); + mutable std::string text; + public: + error() = default; + + template error &operator << (T &&t) { + *temp << std::forward(t); + return *this; + } + const char *what() const noexcept override { + text = temp->str(); + return text.c_str(); + } + }; + #define DEFINE_TYPE(name) struct name ## Impl; static name ## Impl *get(const name ## Ptr &); + DEFINE_TYPE(Connection) + DEFINE_TYPE(Proxy) + DEFINE_TYPE(Object) + DEFINE_TYPE(Message) + DEFINE_TYPE(MessageIter) + #undef DEFINE_TYPE + + class Element; + using ElementList = std::list; + using ElementMap = std::map; + using ElementTuple = std::tuple< + uint8_t, uint16_t, uint32_t, uint64_t, int16_t, int32_t, int64_t, double, bool, std::string, ObjectPath, + ElementList + >; + + class Element { + ElementTuple data; + char signature_ = 0, end_ = 0, index_ = 0; + template void set(T &&t, char signature = detail::DBusSig::value) { + signature_ = signature; + end_ = detail::DBusSig::end; + index_ = static_cast(detail::IndexFromTypeTuple::value); + get() = std::forward(t); + } + public: + template Element(T &&t, typename std::enable_if::value != 0>::type* = nullptr) { set(std::forward(t)); } + Element(ElementList t, int signature) { set(std::move(t), static_cast(signature)); } + + char signature() const { return signature_; } + char end() const { return end_; } + char index() const { return index_; } + bool isContainer() const { return index_ == detail::IndexFromTypeTuple::value; } + template ::value != 0>::type> + bool is() const { return index_ == detail::IndexFromTypeTuple::value; } + template ::value != 0>::type> + const T &get() const { if (!is()) throw error{}; return std::get::value>(data); } + template ::value != 0>::type> + T &get() { if (!is()) throw error{}; return std::get::value>(data); } + }; + + ConnectionPtr eldbus_address_connection_get_impl(const std::string &addr) override; + +#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \ + void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) override; \ + bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) override; +#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \ + eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig) + + eldbus_message_iter_arguments_append_impl_basic(uint8_t, y) + eldbus_message_iter_arguments_append_impl_basic(uint16_t, q) + eldbus_message_iter_arguments_append_impl_basic(uint32_t, u) + eldbus_message_iter_arguments_append_impl_basic(uint64_t, t) + eldbus_message_iter_arguments_append_impl_basic(int16_t, n) + eldbus_message_iter_arguments_append_impl_basic(int32_t, i) + eldbus_message_iter_arguments_append_impl_basic(int64_t, x) + eldbus_message_iter_arguments_append_impl_basic(double, d) + eldbus_message_iter_arguments_append_impl_basic(bool, b) + eldbus_message_iter_arguments_append_impl_basic_impl(const std::string &, std::string, s) + eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath &, ObjectPath, o) + +#undef eldbus_message_iter_arguments_append_impl_basic +#undef eldbus_message_iter_arguments_append_impl_basic_impl + + MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override; + MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override; + MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &it, bool write) override; + MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName) override; + MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override; + bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override; + std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override; + PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override; + std::string eldbus_proxy_interface_get_impl(const ProxyPtr &) override; + void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function &cb) override; + std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override; + MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override; + MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override; + PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override; + MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override; + MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override; + ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override; + std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override; + ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override; + ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override; + ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override; + void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const _Eina_Value * ) > cb) override; + void add_interface_impl( bool fallback, const std::string& pathName, + const ConnectionPtr &connection, + std::vector> &destructors, + const std::string& interfaceName, + std::vector< MethodInfo >& dscrMethods, + std::vector< PropertyInfo >& dscrProperties, + std::vector< SignalInfo >& dscrSignals ) override; + static bool completed(const MessageIterPtr &iter); +private: + MessagePtr call(std::unordered_map, std::function> &mp, const std::string &name, const MessagePtr &msg, MethodType type); +}; + +namespace detail { + template <> struct DBusSigImpl { enum { value = 'y', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'q', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'u', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 't', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'n', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'i', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'x', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'd', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'b', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 's', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = 'o', end = 0 }; }; + template <> struct DBusSigImpl { enum { value = '(', end = ')' }; }; + template <> struct DBusSigImpl { enum { value = '{', end = '}' }; }; + + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + w.eldbus_message_iter_arguments_append_impl(tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + if (!w.eldbus_message_iter_get_and_next_impl(src, tgt)) throw TestDBusWrapper::error{}; + } + }; + template struct Encoder::value>::type> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::type>::encode(w, tgt, static_cast::type>(src)); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + typename std::underlying_type::type v = 0; + Encoder::type>::decode(w, v, src); + tgt = static_cast(v); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const T &src) { + Encoder::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, T &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder::decode(w, tgt, src); + } + }; + template struct EncoderTuple { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { + Encoder>::type>::encode(w, tgt, std::get(src)); + EncoderTuple::encode(w, tgt, src); + } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { + Encoder>::type>::decode(w, std::get(tgt), src); + EncoderTuple::decode(w, tgt, src); + } + }; + template struct EncoderTuple { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::tuple &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'r', ""); + EncoderTuple<0, sizeof...(ARGS), ARGS...>::encode(w, var, src); + } + static void decode(TestDBusWrapper &w, std::tuple &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'r' ); + if( !s ) throw TestDBusWrapper::error{}; + EncoderTuple<0, sizeof...(ARGS), ARGS...>::decode(w, tgt, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::pair &src, char type = 'r') { + auto var = w.eldbus_message_iter_container_new_impl( tgt, type, ""); + Encoder::encode(w, var, src.first); + Encoder::encode(w, var, src.second); + } + static void decode(TestDBusWrapper &w, std::pair &tgt, const TestDBusWrapper::MessageIterPtr &src, char type = 'r') { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, type ); + if( !s ) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt.first, s); + Encoder::decode(w, tgt.second, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const TestDBusWrapper::Variant &src) { + //w.eldbus_message_iter_arguments_append_impl(tgt, src); + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'v', ""); + Encoder::encode(w, var, src.value); + } + static void decode(TestDBusWrapper &w, TestDBusWrapper::Variant &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'v' ); + if( !s ) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt.value, s); + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::vector &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src) + Encoder::encode(w, var, q); + } + static void decode(TestDBusWrapper &w, std::vector &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + while(!TestDBusWrapper::completed(s)) { + tgt.push_back({}); + Encoder::decode(w, tgt.back(), s); + } + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::unordered_map &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src){ + Encoder::value_type>::encode(w, var, q, 'e'); + } + } + static void decode(TestDBusWrapper &w, std::unordered_map &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + while(!TestDBusWrapper::completed(s)) { + std::pair tmp; + Encoder>::decode(w, tmp, s, 'e'); + tgt.insert(std::move(tmp)); + } + } + }; + template struct Encoder> { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const std::array &src) { + auto var = w.eldbus_message_iter_container_new_impl( tgt, 'a', ""); + for(auto &q : src) + Encoder::encode(w, var, q); + } + static void decode(TestDBusWrapper &w, std::array &tgt, const TestDBusWrapper::MessageIterPtr &src) { + auto s = w.eldbus_message_iter_get_and_next_by_type_impl( src, 'a' ); + if( !s ) throw TestDBusWrapper::error{}; + size_t i = 0; + while(!TestDBusWrapper::completed(s)) { + if(i >= tgt.size()) throw TestDBusWrapper::error{}; + Encoder::decode(w, tgt[i], s); + ++i; + } + if( i!=tgt.size()) throw TestDBusWrapper::error{}; + } + }; + template <> struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const Dali::Accessibility::Address &src) { + Encoder>::encode(w, tgt,std::tuple { + src.GetBus(), ObjectPath{ "/org/a11y/atspi/accessible/" + src.GetPath() } } + ); + } + static void decode(TestDBusWrapper &w, Dali::Accessibility::Address &tgt, const TestDBusWrapper::MessageIterPtr &src) { + std::tuple tmp; + Encoder>::decode(w, tmp, src); + static const size_t prefixSize = std::string{ "/org/a11y/atspi/accessible/" }.size(); + tgt = { std::move(std::get<0>(tmp)), std::get<1>(tmp).value.substr(prefixSize) }; + } + }; + template <> struct Encoder { + static void encode(TestDBusWrapper &w, const TestDBusWrapper::MessageIterPtr &tgt, const char *src) { + Encoder::encode(w, tgt, src); + } + }; +} +/// \endcond + +#define DBUS_DEBUG( ... ) \ + do \ + { \ + DBus::debugPrint( __FILE__, __LINE__, __VA_ARGS__ ); \ + } while( 0 ) + +#define DBUS_W DBusWrapper::Installed() + +/** + * @brief Template based, single file, wrapper library around eldbus for DBUS based communication. + * + * Main motivation was missing asynchronous calls in AT-SPI library and difficulties, + * when using eldbus from C++. + * + * The library: + * - takes care of marshalling arguments to and from DBUS calls. + * - allows synchronous and asynchronous calls. + * - allows synchronous and asynchronous listeners on signals. + * - manages all involved objects' lifetimes. + * - errors are passed as optional-alike objects, no exceptions are used. + * - allows setting additional debug-print function for more details about + * what's going on + * + * DBUS's method signatures (and expected return values) are specified as template argument, + * using functor syntax. For example: + * \code{.cpp} + * auto dbus = DBusClient{ ... }; + * auto v = dbus.method(float, float, std::string)>("foo").call(1.0f, 2.0f, "qwe"); + * \endcode + * means (synchronous) call on dbus object, which takes three arguments (thus making call signature \b dds) + * of types float, float and string (float will be automatically converted to double). + * Expected return value is std::tuple, which gives signature (id) - std::tuple acts + * as struct container. Returned value v will be of type ValueOrError>.\n + * Slightly different (asynchronous) example: + * \code{.cpp} + * auto dbus = DBusClient{ ... }; + * std::function)> callback; + * dbus.method(float, float, std::string)>("foo").asyncCall(callback, 1.0f, 2.0f, "qwe"); + * \endcode + * Now the call takes the same arguments and has the same signature. But expected values are different - + * now the signature is simply \b id. ValueOrError acts in this case as placeholder for list of values, + * which DBUS allows as return data. The call itself is asynchronous - instead of expecting reply + * you need to pass a callback, which will be called either with received data and error message. + * + * Library is not thread-safe, the same object shouldn't be called from different threads without + * synchronization. There's no guarantee, that callbacks will be executed on the same thread. + */ +namespace DBus +{ +/// \cond +class DBusServer; +class DBusClient; +class DBusInterfaceDescription; + +/** + * @brief Formats debug message and calls debug printer (if any) with it + */ +void debugPrint( const char* file, size_t line, const char* format, ... ); + +/** + * @brief Sets debug printer callback, which will be called with debug messages + * + * Callback will be called in various moments of DBus activity. First value passed to callback + * is pointer to text, second it's length. Text is ended with 0 (not counted towards it's size), + * user can safely printf it. + */ +void setDebugPrinter( std::function< void( const char*, size_t ) > ); + +struct Error +{ + std::string message; + + Error() = default; + Error( std::string msg ) : message( std::move( msg ) ) + { + bart_assert( !message.empty() ); + } +}; + +struct Success +{ +}; +/// \endcond + +/** + * @brief Value representing data, that came from DBUS or error message + * + * Object of this class either helds series of values (of types ARGS...) + * or error message. This object will be true in boolean context, if has data + * and false, if an error occured. + * It's valid to create ValueOrError object with empty argument list or void: + * \code{.cpp} + * ValueOrError<> v1; + * ValueOrError v2; + * \endcode + * Both mean the same - ValueOrError containing no real data and being a marker, + * wherever operation successed or failed and containing possible error message. + */ +template < typename... ARGS > +class ValueOrError +{ +public: + /** + * @brief Empty constructor. Valid only, if all ARGS types are default constructible. + */ + ValueOrError() = default; + + /** + * @brief Value constructor. + * + * This will be initialized as success with passed in values. + */ + ValueOrError( ARGS... t ) : value( std::move( t )... ) {} + + /** + * @brief Alternative Value constructor. + * + * This will be initialized as success with passed in values. + */ + ValueOrError( std::tuple< ARGS... > t ) : value( std::move( t ) ) {} + + /** + * @brief Error constructor. This will be initialized as failure with given error message. + */ + ValueOrError( Error e ) : error( std::move( e ) ) + { + bart_assert( !error.message.empty() ); + } + + /** + * @brief bool operator. + * + * Returns true, if operation was successful (getValues member is callable), or false + * when operation failed (getError is callable). + */ + explicit operator bool() const + { + return error.message.empty(); + } + + /** + * @brief Returns error message object. + * + * Returns object containing error message associated with the failed operation. + * Only callable, if operation actually failed, otherwise will bart_assert. + */ + const Error& getError() const + { + return error; + } + + /** + * @brief Returns modifiable tuple of held data. + * + * Returns reference to the internal tuple containing held data. + * User can modify (or move) data safely. + * Only callable, if operation actually successed, otherwise will bart_assert. + */ + std::tuple< ARGS... >& getValues() + { + bart_assert( *this ); + return value; + } + + /** + * @brief Returns const tuple of held data. + * + * Returns const reference to the internal tuple containing held data. + * Only callable, if operation actually successed, otherwise will bart_assert. + */ + const std::tuple< ARGS... >& getValues() const + { + bart_assert( *this ); + return value; + } + +protected: + /// \cond + std::tuple< ARGS... > value; + Error error; + /// \endcond +}; + +/// \cond +template <> +class ValueOrError<> +{ +public: + ValueOrError() = default; + ValueOrError( std::tuple<> t ) {} + ValueOrError( Error e ) : error( std::move( e ) ) + { + bart_assert( !error.message.empty() ); + } + + explicit operator bool() const + { + return error.message.empty(); + } + const Error& getError() const + { + return error; + } + std::tuple<>& getValues() + { + bart_assert( *this ); + static std::tuple<> t; + return t; + } + std::tuple<> getValues() const + { + bart_assert( *this ); + return {}; + } + +protected: + Error error; +}; + +template <> +class ValueOrError< void > +{ +public: + ValueOrError() = default; + ValueOrError( Success ) {} + ValueOrError( Error e ) : error( std::move( e ) ) + { + bart_assert( !error.message.empty() ); + } + + explicit operator bool() const + { + return error.message.empty(); + } + const Error& getError() const + { + return error; + } + std::tuple<>& getValues() + { + bart_assert( *this ); + static std::tuple<> t; + return t; + } + std::tuple<> getValues() const + { + bart_assert( *this ); + return {}; + } + +protected: + Error error; +}; + +using ObjectPath = ObjectPath; + +/// \endcond + +/** + * @brief Class used to marshall DBUS's variant type + * + * Minimalistic class, that allows user to specify DBUS variant type + * as argument or return value. You need to pass real type hidden under variant as + * template type \b A. At this point library doesn't allow to expected one of few classes + * as return data in variant. So for example user can't specify method call, which on return + * expects DBUS variant holding either string or int. + */ +template < typename A > +struct EldbusVariant +{ + A value; +}; + +/** + * @brief Namespace for private, internal functions and classes + */ +namespace detail +{ +/// \cond +template < typename T, typename = void > +struct signature; +template < typename... ARGS > +struct signature< std::tuple< ARGS... > >; +template < typename A, typename B > +struct signature< std::pair< A, B > >; +template < typename A > +struct signature< std::vector< A > >; +template < typename A, size_t N > +struct signature< std::array< A, N > >; +template < typename A, typename B > +struct signature< std::unordered_map< A, B > >; +template < typename A, typename B > +struct signature< std::map< A, B > >; +/// \endcond + +/** + * @brief Signature class for marshalling uint8 type. + */ +template <> +struct signature< uint8_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint8_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "y"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint8_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint8_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint16 type. + */ +template <> +struct signature< uint16_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint16_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "q"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint16_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint16_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint32 type. + */ +template <> +struct signature< uint32_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint32_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "u"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint32_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint32_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling uint64 type. + */ +template <> +struct signature< uint64_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "uint64_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "t"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, uint64_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, uint64_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int16 type. + */ +template <> +struct signature< int16_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int16_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "n"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int16_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int16_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int32 type. + */ +template <> +struct signature< int32_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int32_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "i"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int32_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int32_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling int64 type. + */ +template <> +struct signature< int64_t > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "int64_t"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "x"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, int64_t v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, int64_t& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +/** + * @brief Signature class for marshalling double type. + */ +template <> +struct signature< double > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "double"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "d"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, double v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, double& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, float& v2 ) + { + double v = 0; + auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + v2 = static_cast< float >( v ); + return r; + } +}; + +/** + * @brief Signature class for marshalling float type. + */ +template <> +struct signature< float > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "float"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "d"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, float v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, double& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, float& v2 ) + { + double v = 0; + auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + v2 = static_cast< float >( v ); + return r; + } +}; + +/** + * @brief Signature class for marshalling boolean type. + */ +template <> +struct signature< bool > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "bool"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "b"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, bool v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, bool& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +template < typename T > +struct signature< T, typename std::enable_if< std::is_enum< T >::value, void >::type > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "enum"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature::type>::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, T v ) + { + signature::type>::set(iter, static_cast< int64_t >( v )); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, T& v ) + { + typename std::underlying_type::type q = 0; + if (!signature::type>::get(iter, q)) + return false; + + v = static_cast< T >( q ); + return true; + } +}; + +/** + * @brief Signature class for marshalling string type. + * + * Both (const) char * and std::string types are accepted as value to send. + * Only std::string is accepted as value to receive. + */ +template <> +struct signature< std::string > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "string"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "s"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + +// /** +// * @brief Marshals value v as marshalled type into message +// */ +// static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) +// { +// DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); +// } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::string& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } +}; + +template <> +struct signature< ObjectPath > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "path"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "o"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v }); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ObjectPath& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v }); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ObjectPath& v ) + { + return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::string& v ) + { + ObjectPath q; + if (!DBUS_W->eldbus_message_iter_get_and_next_impl(iter, q)) return false; + v = std::move(q.value); + return true; + } +}; + +/** + * @brief Signature class for marshalling (const) char * type. + * + * Both (const) char * and std::string types are accepted as value to send. + * You can't use (const) char * variable type to receive value. + */ +template <> +struct signature< char* > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "string"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "s"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::string& v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const char* v ) + { + DBUS_W->eldbus_message_iter_arguments_append_impl(iter, std::string{ v }); + } +}; +/// \cond + +template < size_t INDEX, typename A, typename... ARGS > +struct signature_tuple_element_type_helper +{ + using type = typename signature_tuple_element_type_helper< INDEX - 1, ARGS... >::type; +}; + +template < typename A, typename... ARGS > +struct signature_tuple_element_type_helper< 0, A, ARGS... > +{ + using type = A; +}; +/// \endcond + +/** + * @brief Helper class to marshall tuples + * + * This class marshals all elements of the tuple value starting at the index INDEX + * and incrementing. This class recursively calls itself with increasing INDEX value + * until INDEX is equal to SIZE, where recursive calling ends. + */ +template < size_t INDEX, size_t SIZE, typename... ARGS > +struct signature_tuple_helper +{ + using current_type = typename signature_tuple_element_type_helper< INDEX, ARGS... >::type; + + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + if( INDEX + 1 >= SIZE ) + return signature< current_type >::name(); + return signature< current_type >::name() + ", " + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::name(); + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< current_type >::sig() + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + signature< current_type >::set( iter, std::get< INDEX >( args ) ); + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::set( iter, args ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + return signature< current_type >::get( iter, std::get< INDEX >( args ) ) && + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::get( iter, args ); + } +}; + +/** + * @brief Helper class to marshall tuples + * + * This class marks end of the tuple marshalling. Members of this class are called + * when INDEX value is equal to SIZE. + */ +template < size_t SIZE, typename... ARGS > +struct signature_tuple_helper< SIZE, SIZE, ARGS... > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return ""; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling tuple of values + * + * This class marshalls tuple of values. This represents + * DBUS struct typle, encoded with character 'r' + */ +template < typename... ARGS > +struct signature< std::tuple< ARGS... > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "tuple<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig() + ")"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::tuple< ARGS... >& args ) + { + auto entry = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'r', ""); + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( entry, args ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::tuple< ARGS... >& args ) + { + auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'r' ); + if (!entry) return false; + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( entry, args ); + } +}; + +/** + * @brief Signature class for marshalling ValueOrError template type + * + * ValueOrError template type is used to marshall list of values passed to + * DBUS (or received from) at the "top" level. For example ss(s) is represented as + * \code{.cpp} ValueOrError> \endcode + * While (ss(s)) is represented as + * \code{.cpp} std::tuple> \endcode + * or + * \code{.cpp} ValueOrError>> \endcode + */ +template < typename... ARGS > +struct signature< ValueOrError< ARGS... > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError<" + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError< ARGS... >& args ) + { + signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::set( iter, args.getValues() ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError< ARGS... >& args ) + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::get( iter, args.getValues() ); + } +}; + +/** + * @brief Signature class for marshalling ValueOrError type + */ +template <> +struct signature< ValueOrError< void > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError< void >& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError< void >& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling ValueOrError<> type + */ +template <> +struct signature< ValueOrError<> > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "ValueOrError<>"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return ""; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const ValueOrError<>& args ) + { + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, ValueOrError<>& args ) + { + return true; + } +}; + +/** + * @brief Signature class for marshalling pair of types + */ +template < typename A, typename B > +struct signature< std::pair< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "pair<" + signature_tuple_helper< 0, 2, A, B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "(" + signature_tuple_helper< 0, 2, A, B >::sig() + ")"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::pair< A, B >& ab, bool dictionary = false ) + { + auto entry = DBUS_W->eldbus_message_iter_container_new_impl( iter, dictionary ? 'e' : 'r', ""); + signature_tuple_helper< 0, 2, A, B >::set( entry, ab ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::pair< A, B >& ab ) + { + auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'r' ); + if (!entry) { + entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, '{' ); + if (!entry) return false; + } + + std::tuple< A, B > ab_tmp; + auto z = signature_tuple_helper< 0, 2, A, B >::get( entry, ab_tmp ); + if( z ) + { + ab.first = std::move( std::get< 0 >( ab_tmp ) ); + ab.second = std::move( std::get< 1 >( ab_tmp ) ); + } + return z; + } +}; + +/** + * @brief Signature class for marshalling std::vector template type + * + * This marshals container's content as DBUS a ascii character type code. + */ +template < typename A > +struct signature< std::vector< A > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "vector<" + signature< A >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a" + signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::vector< A >& v ) + { + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', signature< A >::sig()); + bart_assert( lst ); + for( auto& a : v ) + { + signature< A >::set( lst, a ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::vector< A >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if (!s) return false; + v.clear(); + A a; + while( signature< A >::get( s, a ) ) + v.push_back( std::move( a ) ); + + return true; + } +}; + +/** + * @brief Signature class for marshalling std::array template type + * + * This marshals container's content as DBUS a ascii character type code. + */ +template < typename A, size_t N > +struct signature< std::array< A, N > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "array<" + signature< A >::name() + ", " + std::to_string( N ) + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a" + signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::array< A, N >& v ) + { + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', signature< A >::sig()); + bart_assert( lst ); + for( auto& a : v ) + { + signature< A >::set( lst, a ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::array< A, N >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if ( !s ) + return false; + for( auto& a : v ) + { + if( !signature< A >::get( s, a ) ) + return false; + } + return true; + } +}; + +/** + * @brief Signature class for marshalling EldbusVariant type + * + * This marshals variant's content as DBUS v ascii character type code. + */ +template < typename A > +struct signature< EldbusVariant< A > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "variant<" + signature< A >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "v"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const EldbusVariant< A >& v ) + { + set( iter, v.value ); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + auto var = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'v', signature< A >::sig()); + signature< A >::set( var, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, EldbusVariant< A >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'v' ); + if( !s ) + return false; + return signature< A >::get( s, v.value ); + } +}; + +/** + * @brief Signature class for marshalling std::unordered_map template type + * + * This marshals container's content as DBUS {} ascii character type code. + * Note, that library doesnt check, if the key is basic type, as DBUS + * specification mandates. + * User can always exchange std::unordered_map for std::map and the reverse. + * User can receive such values as std::vector of std::pair values. + * Order of such values is unspecified. + */ +template < typename A, typename B > +struct signature< std::unordered_map< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "unordered_map<" + signature< A >::name() + ", " + signature< B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::unordered_map< A, B >& v ) + { + auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', sig); + bart_assert( lst ); + for( auto& a : v ) + { + signature< std::pair< A, B > >::set( lst, a, true ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::unordered_map< A, B >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + v.clear(); + if( !s ) + return false; + std::pair< A, B > a; + while( signature< std::pair< A, B > >::get( s, a ) ) + v.insert( std::move( a ) ); + return true; + } +}; + +/** + * @brief Signature class for marshalling std::unordered_map template type + * + * This marshals container's content as DBUS {} ascii character type code. + * Note, that library doesnt check, if the key is basic type, as DBUS + * specification mandates. + * User can always exchange std::unordered_map for std::map and the reverse. + * User can receive such values as std::vector of std::pair values. + * Order of such values is unspecified. + */ +template < typename A, typename B > +struct signature< std::map< A, B > > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "map<" + signature< A >::name() + ", " + signature< B >::name() + ">"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const std::map< A, B >& v ) + { + auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}"; + auto lst = DBUS_W->eldbus_message_iter_container_new_impl( iter, 'a', sig); + bart_assert( lst ); + for( auto& a : v ) + { + signature< std::pair< A, B > >::set( lst, a, true ); + } + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static bool get( const DBusWrapper::MessageIterPtr &iter, std::map< A, B >& v ) + { + auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl( iter, 'a' ); + if( !s ) + return false; + std::pair< A, B > a; + while( signature< std::pair< A, B > >::get( s, a ) ) + v.insert( std::move( a ) ); + return true; + } +}; + +/** + * @brief Signature helper class for marshalling const reference types + */ +template < typename A > +struct signature< const A& > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "const " + signature< A >::name() + "&"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/** + * @brief Signature helper class for marshalling reference types + */ +template < typename A > +struct signature< A& > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return signature< A >::name() + "&"; + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/** + * @brief Signature helper class for marshalling const types + */ +template < typename A > +struct signature< const A > +{ + /** + * @brief Returns name of type marshalled, for informative purposes + */ + static std::string name() + { + return "const " + signature< A >::name(); + } + + /** + * @brief Returns DBUS' signature of type marshalled + */ + static std::string sig() + { + return signature< A >::sig(); + } + + /** + * @brief Marshals value v as marshalled type into message + */ + static void set( const DBusWrapper::MessageIterPtr &iter, const A& v ) + { + signature< A >::set( iter, v ); + } + + /** + * @brief Marshals value from marshalled type into variable v + */ + static void get( const DBusWrapper::MessageIterPtr &iter, A& v ) + { + signature< A >::get( iter, v ); + } +}; + +/// \cond +using CallId = DBusWrapper::CallId; + +template < typename ValueType > +ValueType unpackValues( CallId callId, const DBusWrapper::MessagePtr &msg ) +{ + auto iter = DBUS_W->eldbus_message_iter_get_impl( msg, false ); + ValueType r; + + if( iter ) + { + if( !signature< ValueType >::get( iter, r ) ) + { + DBUS_DEBUG( "ValueType is %s", signature< ValueType >::name().c_str() ); + r = Error{"call " + std::to_string( callId.id ) + ": failed to unpack values, got signature '" + + DBUS_W->eldbus_message_signature_get_impl( msg ) + "', expected '" + signature< ValueType >::sig() + "'"}; + } + } + else + { + r = Error{"call " + std::to_string( callId.id ) + ": failed to get iterator"}; + } + return r; +} + +inline void packValues_helper( const DBusWrapper::MessageIterPtr& ) {} + +template < typename A, typename... ARGS > +void packValues_helper( const DBusWrapper::MessageIterPtr &iter, A&& a, ARGS&&... r ) +{ + signature< A >::set( iter, std::forward< A >( a ) ); + packValues_helper( iter, std::forward< ARGS >( r )... ); +} + +template < typename... ARGS > +void packValues( CallId callId, const DBusWrapper::MessagePtr &msg, ARGS&&... r ) +{ + auto iter = DBUS_W->eldbus_message_iter_get_impl( msg, true ); + packValues_helper( iter, std::forward< ARGS >( r )... ); +} + +template < typename > +struct ReturnType; +template < typename R, typename... ARGS > +struct ReturnType< R( ARGS... ) > +{ + using type = R; +}; + +template < typename R, typename... ARGS > +struct ReturnType< std::function< R( ARGS... ) > > +{ + using type = R; +}; + +template < int... > +struct sequence +{ +}; + +template < int N, int... S > +struct sequence_gen : sequence_gen< N - 1, N - 1, S... > +{ +}; + +template < int... S > +struct sequence_gen< 0, S... > +{ + typedef sequence< S... > type; +}; + +template < typename C, typename... ARGS > +struct apply_helper +{ + const std::function< C >& c; + const std::tuple< ARGS... >& args; + + template < int... S > + auto apply_2( sequence< S... > ) const -> decltype( c( std::get< S >( args )... ) ) + { + return c( std::get< S >( args )... ); + } + auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) ) + { + return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ); + } +}; + +template < typename C, typename A, typename... ARGS > +struct apply_helper_2 +{ + const std::function< C >& c; + const A& a; + const std::tuple< ARGS... >& args; + + template < int... S > + auto apply_2( sequence< S... > ) const -> decltype( c( a, std::get< S >( args )... ) ) + { + return c( a, std::get< S >( args )... ); + } + auto apply_1() const -> decltype( apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ) ) + { + return apply_2( typename sequence_gen< sizeof...( ARGS ) >::type() ); + } +}; + +template < typename C, typename... ARGS > +auto apply( const std::function< C >& c, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type +{ + apply_helper< C, ARGS... > ah{c, args}; + return ah.apply_1(); +} + +template < typename C, typename D, typename... ARGS > +auto apply( const std::function< C >& c, const D& d, const std::tuple< ARGS... >& args ) -> typename ReturnType< C >::type +{ + apply_helper_2< C, D, ARGS... > ah{c, d, args}; + return ah.apply_1(); +} + +struct ConnectionState +{ + DBusWrapper::ConnectionPtr connection; + DBusWrapper::ObjectPtr object; + DBusWrapper::ProxyPtr proxy, propertiesProxy; +}; + +template < typename RETTYPE, typename... ARGS > +RETTYPE call( CallId callId, const ConnectionState& connectionState, bool property, const std::string& funcName, const ARGS&... args ) +{ + const auto &proxy = property ? connectionState.propertiesProxy : connectionState.proxy; + if( !proxy ) + { + DBUS_DEBUG( "call %d: not initialized", callId.id ); + return Error{"not initialized"}; + } + + DBUS_DEBUG( "call %d: calling '%s'", callId.id, funcName.c_str() ); + auto msg = DBUS_W->eldbus_proxy_method_call_new_impl(proxy, funcName); + if( !msg ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + return Error{"failed to create message"}; + } + + detail::packValues( callId, msg, args... ); + auto reply = DBUS_W->eldbus_proxy_send_and_block_impl( proxy, msg ); + DBUS_DEBUG( "call %d: calling '%s' done", callId.id, funcName.c_str() ); + if( !reply ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + return Error{"eldbus returned null as reply"}; + } + std::string errname, errmsg; + if( DBUS_W->eldbus_message_error_get_impl( reply, errname, errmsg ) ) + { + DBUS_DEBUG( "call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str() ); + return Error{errname + ": " + errmsg}; + } + DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, + DBUS_W->eldbus_message_signature_get_impl( reply ).c_str() ); + return detail::unpackValues< RETTYPE >( callId, reply ); +} + +template < typename RETTYPE, typename... ARGS > +void asyncCall( CallId callId, const ConnectionState &connectionState, + bool property, const std::string& funcName, + std::function< void( RETTYPE ) > callback, const ARGS&... args ) +{ + const auto &proxy = property ? connectionState.propertiesProxy : connectionState.proxy; + if( !proxy ) + { + DBUS_DEBUG( "call %d: not initialized", callId.id ); + callback( Error{"not initialized"} ); + return; + } + + auto msg = DBUS_W->eldbus_proxy_method_call_new_impl( proxy, funcName ); + if( !msg ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + callback( Error{"failed to create message"} ); + return; + } + + detail::packValues( callId, msg, args... ); + auto pending = DBUS_W->eldbus_proxy_send_impl( proxy, msg, [callback, callId, proxy]( const DBusWrapper::MessagePtr &reply ) { + DBUS_DEBUG( "call %d: calling done", callId.id ); + if( !reply ) + { + DBUS_DEBUG( "call %d: failed", callId.id ); + callback( Error{"eldbus returned null as reply"} ); + } + else + { + std::string errname, errmsg; + if( DBUS_W->eldbus_message_error_get_impl( reply, errname, errmsg ) ) + { + DBUS_DEBUG( "call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str() ); + callback( Error{errname + ": " + errmsg} ); + } + else + { + DBUS_DEBUG( "call %d: got reply with signature '%s'", callId.id, + DBUS_W->eldbus_message_signature_get_impl( reply ).c_str() ); + callback( detail::unpackValues< RETTYPE >( callId, reply ) ); + } + } + } + ); + if( pending ) + { + DBUS_DEBUG( "call %d: call sent", callId.id ); + } + else + { + DBUS_DEBUG( "call %d: failed to send call", callId.id ); + callback( Error{"failed to send call"} ); + } +} + +inline void displayDebugCallInfo( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName ) +{ + DBUS_DEBUG( "call %d: %s iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() ); +} + +inline void displayDebugCallInfoSignal( CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName ) +{ + DBUS_DEBUG( "call %d: %s signal iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str() ); +} + +inline void displayDebugCallInfoProperty( CallId callId, const std::string& funcName, std::string info, const std::string& interfaceName, + const std::string& propertyName ) +{ + DBUS_DEBUG( "call %d: %s iname = %s pname = %s", callId.id, info.c_str(), interfaceName.c_str(), propertyName.c_str() ); +} + +using StringStorage = DBusWrapper::StringStorage; + +template < typename A, typename... ARGS > +struct EldbusArgGenerator_Helper +{ + static void add( std::vector< std::pair >& r ) + { + auto s = r.size(); + auto sig = signature< A >::sig(); + bart_assert( !sig.empty() ); + auto name = "p" + std::to_string( s + 1 ); + r.push_back({ std::move(sig), std::move(name) }); + EldbusArgGenerator_Helper::add( r ); + } +}; + +template <> +struct EldbusArgGenerator_Helper< void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; + +template <> +struct EldbusArgGenerator_Helper< ValueOrError< void >, void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; +template <> +struct EldbusArgGenerator_Helper< ValueOrError<>, void > +{ + static void add( std::vector< std::pair >& ) + { + } +}; + +template < typename... ARGS > +struct EldbusArgGenerator_Helper< std::tuple< ARGS... > > +{ + static void add( std::vector< std::pair >& r ) + { + EldbusArgGenerator_Helper< ARGS..., void >::add( r ); + } +}; + +template < typename RetType > +struct dbus_interface_return_type_traits +{ + using type = ValueOrError< RetType >; +}; + +template < typename... ARGS > +struct dbus_interface_return_type_traits< ValueOrError< ARGS... > > +{ + using type = ValueOrError< ARGS... >; +}; + +template < typename T > +struct dbus_interface_traits; +template < typename RetType, typename... ARGS > +struct dbus_interface_traits< RetType( ARGS... ) > +{ + using Ret = typename dbus_interface_return_type_traits< RetType >::type; + using SyncCB = std::function< Ret( ARGS... ) >; + using AsyncCB = std::function< void( std::function< void( Ret ) >, ARGS... ) >; + using VEArgs = ValueOrError< ARGS... >; +}; + +template < typename T > +struct EldbusArgGenerator_Args; +template < typename RetType, typename... ARGS > +struct EldbusArgGenerator_Args< RetType( ARGS... ) > +{ + static std::string name() + { + return signature_tuple_helper< 0, sizeof...( ARGS ), ARGS... >::name(); + } + static std::vector< std::pair > get() + { + std::vector< std::pair > tmp; + EldbusArgGenerator_Helper< ARGS..., void >::add( tmp ); + return tmp; + } +}; + +template < typename T > +struct EldbusArgGenerator_ReturnType; +template < typename RetType, typename... ARGS > +struct EldbusArgGenerator_ReturnType< RetType( ARGS... ) > +{ + static std::string name() + { + return signature< RetType >::name(); + } + static std::vector< std::pair > get( ) + { + std::vector< std::pair > tmp; + EldbusArgGenerator_Helper< RetType, void >::add( tmp ); + return tmp; + } +}; + +template < typename T > +struct EldbusArgGenerator_ReturnType; +template < typename... ARGS > +struct EldbusArgGenerator_ReturnType< void( ARGS... ) > +{ + static std::string name() + { + return ""; + } + static std::vector< std::pair > get( ) + { + return {}; + } +}; +/// \endcond +} + +using ConnectionType = DBusWrapper::ConnectionType; + +/** + * @brief Class representing client's end of DBUS connection + * + * Allows calling (synchronous and asynchronos) methods on selected interface + * Allows (synchronous and asynchronos) setting / getting properties. + * Allows registering signals. + */ +class DBusClient +{ + /// \cond + struct ConnectionInfo + { + std::string interfaceName, busName, pathName; + }; + /// \endcond +public: + /** + * @brief Default constructor, creates non-connected object. + */ + DBusClient() = default; + + /** + * @brief Connects to dbus choosen by tp, using given arguments + * + * @param bus_name name of the bus to connect to + * @param path_name object's path + * @param interface_name interface name + */ + DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_, + ConnectionType tp ); + + /** + * @brief Connects to dbus using connection conn + * + * @param bus_name name of the bus to connect to + * @param path_name object's path + * @param interface_name interface name + * @param conn connection object from getDBusConnectionByType call + */ + DBusClient( std::string busName_, std::string pathName_, std::string interfaceName_, + const DBusWrapper::ConnectionPtr &conn = {} ); + + /** + * @brief Destructor object. + * + * All signals added will be disconnected. + * All asynchronous calls will be cancelled, their callback's will be called + * with failure message. + */ + ~DBusClient() = default; + DBusClient( const DBusClient& ) = delete; + DBusClient( DBusClient&& ) = default; + + DBusClient& operator=( DBusClient&& ) = default; + DBusClient& operator=( const DBusClient& ) = delete; + + /** + * @brief bool operator + * + * Returns true, if object is connected to DBUS + */ + explicit operator bool() const + { + return bool( connectionState->proxy ); + } + + /** + * @brief Helper class for calling a method + * + * Template type T defines both arguments sent to the method + * and expected values. Receiving different values will be reported as + * error. For example: + * \code{.cpp} Method \endcode + * defines method, which takes two arguments (two floats) and return + * single value of type int. + */ + template < typename T > + struct Method + { + /// \cond + using RetType = typename detail::dbus_interface_traits< T >::Ret; + const detail::ConnectionState &connectionState; + std::string funcName; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + /// \endcond + + /** + * @brief Executes synchronous call on DBUS's method + * + * The function returns ValueOrError<...> object, which + * contains either received values or error message. + * + * @param args arguments to pass to the method + */ + template < typename... ARGS > + RetType call( const ARGS&... args ) + { + detail::CallId callId; + detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName ); + return detail::call< RetType >( callId, connectionState, false, funcName, args... ); + } + + /** + * @brief Executes asynchronous call on DBUS's method + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + * @param args arguments to pass to the method + */ + template < typename... ARGS > + void asyncCall( std::function< void( RetType ) > callback, const ARGS&... args ) + { + detail::CallId callId; + detail::displayDebugCallInfo( callId, funcName, info, connectionInfo->interfaceName ); + detail::asyncCall< RetType >( callId, connectionState, false, funcName, std::move( callback ), args... ); + } + }; + + /** + * @brief Helper class for calling a property + * + * Template type T defines type of the value hidden under property. + * Note, that library automatically wraps both sent and received value into + * DBUS's wrapper type. + */ + template < typename T > + struct Property + { + /// \cond + using RetType = typename detail::dbus_interface_return_type_traits< T >::type; + using VariantRetType = typename detail::dbus_interface_return_type_traits< EldbusVariant< T > >::type; + const detail::ConnectionState &connectionState; + std::string propName; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + /// \endcond + + /** + * @brief executes synchronous get on property + * + * The function returns ValueOrError<...> object, which + * contains either received values or error message. + */ + RetType get() + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName ); + auto z = detail::call< VariantRetType >( callId, connectionState, true, "Get", connectionInfo->interfaceName, propName ); + if( !z ) + return z.getError(); + return {std::get< 0 >( z.getValues() ).value}; + } + + /** + * @brief executes asynchronous get on property + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + */ + void asyncGet( std::function< void( RetType ) > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Get", info, connectionInfo->interfaceName, propName ); + auto cc = [callback]( VariantRetType reply ) { + if( reply ) + callback( std::move( std::get< 0 >( reply.getValues() ).value ) ); + else + callback( reply.getError() ); + }; + detail::asyncCall< VariantRetType >( callId, connectionState, true, "Get", std::move( cc ), connectionInfo->interfaceName, propName ); + } + + /** + * @brief executes synchronous set on property + * + * The function returns ValueOrError object, with + * possible error message. + */ + ValueOrError< void > set( const T& r ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName ); + EldbusVariant< T > variantValue{std::move( r )}; + return detail::call< ValueOrError< void > >( callId, connectionState, true, "Set", connectionInfo->interfaceName, propName, variantValue ); + } + + /** + * @brief executes asynchronous get on property + * + * The function calls callback with either received values or error message. + * + * @param callback callback functor, which will be called with return value(s) or error message + */ + void asyncSet( std::function< void( ValueOrError< void > ) > callback, const T& r ) + { + detail::CallId callId; + detail::displayDebugCallInfoProperty( callId, "Set", info, connectionInfo->interfaceName, propName ); + EldbusVariant< T > variantValue{std::move( r )}; + detail::asyncCall< ValueOrError< void > >( callId, connectionState, true, "Set", std::move( callback ), connectionInfo->interfaceName, propName, variantValue ); + } + }; + + /** + * @brief Constructs Property<...> object for calling properties + * + * The function constructs and returns proxy object for calling property. + * + * @param propName property name to set and / or query + */ + template < typename PropertyType > + Property< PropertyType > property( std::string propName ) + { + return Property< PropertyType >{*connectionState, std::move( propName ), info, connectionInfo}; + } + + /** + * @brief Constructs Method<...> object for calling methods + * + * The function constructs and returns proxy object for calling method. + * + * @param funcName function name to call + */ + template < typename MethodType > + Method< MethodType > method( std::string funcName ) + { + return Method< MethodType >{*connectionState, std::move( funcName ), info, connectionInfo}; + } + + /** + * @brief Registers notification callback, when property has changed + * + * The callback will be called with new value, when property's value has changed. + * Note, that template type V must match expected type, otherwise undefined behavior will occur, + * there's no check for this. + */ + template < typename V > + void addPropertyChangedEvent( std::string propertyName, std::function< void( V ) > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoSignal( callId, propertyName, info, connectionInfo->interfaceName ); + DBUS_DEBUG( "call %d: adding property", callId.id ); + auto &cI = this->connectionInfo; + DBUS_W->add_property_changed_event_listener_impl(connectionState->proxy, cI->interfaceName, propertyName, + [callback]( const _Eina_Value *newValue ) { + V val = 0; + if( !getFromEinaValue( newValue, &val ) ) + { + DBUS_DEBUG( "unable to get property's value" ); + return; + } + callback( val ); + }); + } + + /** + * @brief Registers callback on the DBUS' signal + * + * The function registers callback signalName. When signal comes, callback will be called. + * Callback object will exists as long as signal is registered. You can unregister signal + * by destroying DBusClient object. + * + * @param signalName name of the signal to register + * @param callback callback to call + */ + template < typename SignalType > + void addSignal( std::string signalName, std::function< SignalType > callback ) + { + detail::CallId callId; + detail::displayDebugCallInfoSignal( callId, signalName, info, connectionInfo->interfaceName ); + DBUS_W->eldbus_proxy_signal_handler_add_impl( connectionState->proxy, signalName, + [callId, callback, signalName]( const DBusWrapper::MessagePtr &msg ) -> void { + std::string errname, aux; + if( DBUS_W->eldbus_message_error_get_impl( msg, errname, aux ) ) + { + DBUS_DEBUG( "call %d: Eldbus error: %s %s", callId.id, errname.c_str(), aux.c_str() ); + return; + } + DBUS_DEBUG( "call %d: received signal with signature '%s'", callId.id, DBUS_W->eldbus_message_signature_get_impl( msg ).c_str() ); + using ParamsType = typename detail::dbus_interface_traits< SignalType >::VEArgs; + auto params = detail::unpackValues< ParamsType >( callId, msg ); + if( !params ) + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, params.getError().message.c_str() ); + return; + } + try + { + detail::apply( callback, params.getValues() ); + } + catch( ... ) + { + DBUS_DEBUG( "unhandled exception" ); + bart_assert( 0 ); + } + }); + } + +private: + /// \cond + std::unique_ptr connectionState{ new detail::ConnectionState }; + std::string info; + std::shared_ptr< ConnectionInfo > connectionInfo; + + static bool getFromEinaValue(const _Eina_Value *v, void *dst); + /// \endcond +}; + +/** + * @brief Helper class describing DBUS's server interface + * + */ +class DBusInterfaceDescription +{ + friend class DBusServer; + +public: + /// \cond + using MethodInfo = DBusWrapper::MethodInfo; + using SignalInfo = DBusWrapper::SignalInfo; + using PropertyInfo = DBusWrapper::PropertyInfo; + using SignalId = DBusWrapper::SignalId; + /// \endcond + + /** + * @brief Creates empty interface description with given name + * + * @param interfaceName name of the interface + */ + DBusInterfaceDescription( std::string interfaceName ); + + /** + * @brief adds new, synchronous method to the interface + * + * When method memberName is called on DBUS, callback functor will be called + * with values received from DBUS. callback won't be called, if method was + * called with invalid signature. Value returned from functor (or error message) + * will be marshalled back to the caller. + * + * Template type T defines both arguments sent to the method + * and expected values. Receiving different values will be reported as + * error. For example: + * \code{.cpp} Method \endcode + * defines method, which takes two arguments (two floats) and return + * single value of type int. + * + * @param memberName name of the method + * @param callback functor, which will be called + */ + template < typename T > + void addMethod( const std::string& memberName, typename detail::dbus_interface_traits< T >::SyncCB callback ) + { + detail::CallId callId; + MethodInfo mi; + methods.push_back( std::move( mi ) ); + auto& z = methods.back(); + z.in = detail::EldbusArgGenerator_Args< T >::get( ); + z.out = detail::EldbusArgGenerator_ReturnType< T >::get( ); + z.memberName = memberName; + DBUS_DEBUG( "call %d: method %s, in %s, out %s", callId.id, memberName.c_str(), + detail::EldbusArgGenerator_Args< T >::name().c_str(), + detail::EldbusArgGenerator_ReturnType< T >::name().c_str() ); + z.callback = construct< T >( callId, callback ); + z.id = callId; + } + + /** + * @brief adds new, synchronous property to the interface + * + * When property memberName is called on DBUS, respective callback functor will be called + * with values received from DBUS. callback won't be called, if method was + * called with invalid signature. Value returned from functor (or error message) + * will be marshalled back to the caller. + * + * Template type T defines type of the value hidden under property. + * Note, that library automatically wraps both sent and received value into + * DBUS's wrapper type. + * + * @param memberName name of the method + * @param getter functor, which will be called when property is being read + * @param setter functor, which will be called when property is being set + */ + template < typename T > + void addProperty( const std::string& memberName, std::function< ValueOrError< T >() > getter, std::function< ValueOrError< void >( T ) > setter ) + { + properties.push_back( {} ); + auto& z = properties.back(); + z.memberName = memberName; + z.typeSignature = detail::signature< T >::sig(); + if( getter ) + { + detail::CallId getterId; + z.getterId = getterId; + DBUS_DEBUG( "call %d: property %s (get) type %s", getterId.id, memberName.c_str(), detail::signature< T >::name().c_str() ); + z.getCallback = [=]( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &dst ) -> std::string { + try + { + auto v = detail::apply( getter, std::tuple<>{} ); + if( v ) + { + detail::signature< T >::set( dst, std::get< 0 >( v.getValues() ) ); + DBUS_DEBUG( "call %d: success", getterId.id ); + return ""; + } + DBUS_DEBUG( "call %d: failed: %s", getterId.id, v.getError().message.c_str() ); + return v.getError().message; + } + catch( std::exception& e ) + { + return std::string( "unhandled exception (" ) + e.what() + ")"; + } + catch( ... ) + { + return "unhandled exception"; + } + }; + } + if( setter ) + { + detail::CallId setterId; + z.setterId = setterId; + DBUS_DEBUG( "call %d: property %s (set) type %s", setterId.id, memberName.c_str(), detail::signature< T >::name().c_str() ); + z.setCallback = [=]( const DBusWrapper::MessagePtr &src, const DBusWrapper::MessageIterPtr &src_iter ) -> std::string { + std::tuple< T > value; + auto src_signature = DBUS_W->eldbus_message_iter_signature_get_impl( src_iter ); + if( detail::signature< T >::get( src_iter, std::get< 0 >( value ) ) ) + { + try + { + auto v = detail::apply( setter, std::move( value ) ); + if( v ) + { + DBUS_DEBUG( "call %d: success", setterId.id ); + return ""; + } + DBUS_DEBUG( "call %d: failed: %s", setterId.id, v.getError().message.c_str() ); + return v.getError().message; + } + catch( std::exception& e ) + { + return std::string( "unhandled exception (" ) + e.what() + ")"; + } + catch( ... ) + { + return "unhandled exception"; + } + } + DBUS_DEBUG( "call %d: failed to unpack values, got signature '%s', expected '%s'", setterId.id, + src_signature.c_str(), detail::signature< T >::sig().c_str() ); + return "call " + std::to_string( setterId.id ) + ": failed to unpack values, got signature '" + + src_signature + "', expected '" + detail::signature< T >::sig() + "'"; + }; + } + } + + /** + * @brief adds new signal to the interface + * + * Template types ARGS defines values, which will be emited with the signal + * + * @param memberName name of the method + */ + template < typename... ARGS > + SignalId addSignal( const std::string& memberName ) + { + detail::CallId callId; + signals.push_back( {} ); + auto& z = signals.back(); + z.memberName = memberName; + z.args = detail::EldbusArgGenerator_Args< void( ARGS... ) >::get( DBUS_W->Strings ); + z.id = callId; + DBUS_DEBUG( "call %d: signal %s", callId.id, memberName.c_str() ); + return SignalId{callId}; + } + +private: + /// \cond + std::vector< MethodInfo > methods; + std::vector< PropertyInfo > properties; + std::vector< SignalInfo > signals; + std::string interfaceName; + + template < typename T > + std::function< DBusWrapper::MessagePtr( const DBusWrapper::MessagePtr &msg ) > construct( detail::CallId callId, + typename detail::dbus_interface_traits< T >::SyncCB callback ) + { + using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs; + return [=]( const DBusWrapper::MessagePtr &msg ) -> DBusWrapper::MessagePtr { + DBUS_DEBUG( "call %d: entering", callId.id ); + DBusWrapper::MessagePtr ret = {}; + auto args = detail::unpackValues< VEArgs >( callId, msg ); + if( args ) + { + try + { + auto v = detail::apply( callback, std::move( args.getValues() ) ); + if( v ) + { + DBUS_DEBUG( "call %d: success", callId.id ); + ret = DBUS_W->eldbus_message_method_return_new_impl( msg ); + detail::packValues( callId, ret, v ); + } + else + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, v.getError().message.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", v.getError().message ); + } + } + catch( std::exception& e ) + { + auto txt = std::string( "unhandled exception (" ) + e.what() + ")"; + DBUS_DEBUG( "call %d: failed: %s", callId.id, txt.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", txt ); + } + catch( ... ) + { + DBUS_DEBUG( "call %d: failed: %s", callId.id, "unhandled exception" ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.Failed", "unhandled exception" ); + } + } + else + { + std::ostringstream err; + err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << DBUS_W->eldbus_message_signature_get_impl( msg ) << "'"; + auto str = err.str(); + DBUS_DEBUG( "call %d: failed: %s", callId.id, str.c_str() ); + ret = DBUS_W->eldbus_message_error_new_impl( msg, "org.freedesktop.DBus.Error.InvalidArgs", str ); + } + return ret; + }; + } + /// \endcond +}; + +/** + * @brief Class representing server's end of DBUS connection + * + * Allows listening (synchronously and asynchronosly) on methods on selected interface + * Allows listening (synchronously and asynchronosly) on setting / getting properties. + * Allows emiting signals. + */ +class DBusServer +{ +public: + /** + * @brief Constructs non-connected dbus server. + */ + DBusServer() = default; + + /** + * @brief Constructs dbus server on either system or user dbus connection. + */ + DBusServer( ConnectionType tp ); + + /** + * @brief Constructs dbus server on connection from getDBusConnectionByType + */ + DBusServer( const DBusWrapper::ConnectionPtr &conn ); + + /** + * @brief Destructor + * + * Destructor will properly destroy everything. Destructor will cancel + * pending replies. + */ + ~DBusServer() = default; + + DBusServer( const DBusServer& ) = delete; + DBusServer( DBusServer&& ) = default; + + DBusServer& operator=( DBusServer&& ) = default; + DBusServer& operator=( const DBusServer& ) = delete; + + /** + * @brief Registers interface on given path name + * + * @param pathName path object to register interface on. + * @param dscr + * @param fallback + */ + void addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback = false ); + + /** + * @brief Gets bus name of the current connection (must be connected) + */ + std::string getBusName() const; + + /** + * @brief Returns connection object for this dbus server object + * + * @return connection object + */ + DBusWrapper::ConnectionPtr getConnection(); + + /** + * @brief Emits signal + * + * Emits signal based only on data passed to the function + * + * @param signal identifier of the signal + * @param args values to emit + */ + template < typename... ARGS > + void emit2( const std::string& path, const std::string& interfaceName, + const std::string& signalName, const ARGS&... args ) + { + auto msg = DBUS_W->eldbus_message_signal_new_impl( path, interfaceName, signalName ); + detail::CallId id; + detail::packValues( id, msg, args... ); + DBUS_W->eldbus_connection_send_impl( connection, msg ); + } + + /** + * @brief Returns current object path, when handling call to property / method + * + * User can call this function from inside callback used to handle property / method calls. + * It will retrieve object's path used in the call. Note, that in asynchronous handling + * of those calls user need to retrieve and store the current object / current connection + * as the value will change at the moment user's callback handling will exit. For example: + * \code{.cpp} + * DBusInterfaceDescription interface{"name"}; + * auto handler_later = [](std::function done_cb) { + * // process something later on + * DBusServer::getCurrentObjectPath(); // this will return empty string + * }; + * interface.addAsyncMethod("m", [=](std::function done_cb) { + * DBusServer::getCurrentObjectPath(); // this will current object's path + * + * // do some processing later on and call done_cb, when it's done + * register_to_call_sometime_later_on(std::move(done_cb)); + * }; + * \endcode + */ + static std::string getCurrentObjectPath() { return currentObjectPath; } + + /** + * @brief Returns current connection object, when handling call to property / method + * + * User can call this function from inside callback used to handle property / method calls. + * It will retrieve object's path used in the call. Note, that in asynchronous handling + * of those calls user need to retrieve and store the current object / current connection + * as the value will change at the moment user's callback handling will exit. For example: + * \code{.cpp} + * DBusInterfaceDescription interface{"name"}; + * auto handler_later = [](std::function done_cb) { + * // process something later on + * DBusServer::getCurrentObjectPath(); // this will return empty string + * }; + * interface.addAsyncMethod("m", [=](std::function done_cb) { + * DBusServer::getCurrentObjectPath(); // this will current object's path + * + * // do some processing later on and call done_cb, when it's done + * register_to_call_sometime_later_on(std::move(done_cb)); + * }; + * \endcode + */ + static const DBusWrapper::ConnectionPtr &getCurrentConnection() { return currentConnection; } + + /// \cond + class CurrentObjectSetter + { + public: + CurrentObjectSetter( DBusWrapper::ConnectionPtr con, std::string path ) + { + currentObjectPath = std::move(path); + currentConnection = std::move( con ); + } + ~CurrentObjectSetter() + { + currentObjectPath = ""; + currentConnection = {}; + } + CurrentObjectSetter( const CurrentObjectSetter& ) = delete; + CurrentObjectSetter( CurrentObjectSetter&& ) = delete; + void operator=( const CurrentObjectSetter& ) = delete; + void operator=( CurrentObjectSetter&& ) = delete; + }; + /// \endcond + +private: + /// \cond + DBusWrapper::ConnectionPtr connection; + struct DestructorObject { + std::vector> destructors; + ~DestructorObject() { + for(auto &a : destructors) a(); + } + }; + + std::unique_ptr destructorObject { new DestructorObject() }; + static thread_local std::string currentObjectPath; + static thread_local DBusWrapper::ConnectionPtr currentConnection; + + /// \endcond +}; + +/// \cond +DBusWrapper::ConnectionPtr getDBusConnectionByType( ConnectionType tp ); +DBusWrapper::ConnectionPtr getDBusConnectionByName( const std::string& name ); +std::string getConnectionName( const DBusWrapper::ConnectionPtr& ); +/// \endcond +} + +/// \cond +namespace std +{ +template < size_t INDEX, typename... ARGS > +inline auto get( DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) & +{ + return std::get< INDEX >( v.getValues() ); +} + +template < size_t INDEX, typename... ARGS > +inline auto get( const DBus::ValueOrError< ARGS... >& v ) -> decltype( std::get< INDEX >( v.getValues() ) ) +{ + return std::get< INDEX >( v.getValues() ); +} +} +/// \endcond + +#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Accessible.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Accessible.cpp new file mode 100644 index 0000000..9b103e8 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Accessible.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * + */ + +// Need to override adaptor classes for toolkit test harness, so include +// test harness headers before dali headers. +#include + +#include +#include + +#include +#include + +#include + +void utc_dali_toolkit_accessibility_accessible_startup(void) +{ + test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); +} + +void utc_dali_toolkit_accessibility_accessible_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int utcDaliAccessibilityCheckBoxButtonGetStates(void) +{ + ToolkitTestApplication application; + + auto check_box_button = Toolkit::CheckBoxButton::New(); + auto q = Dali::Accessibility::Accessible::Get( check_box_button ); + DALI_TEST_CHECK( q ); + auto states = q->GetStates(); + DALI_TEST_EQUALS( (int) states[ Dali::Accessibility::State::SELECTABLE ], (int) true, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityCheckLabelText(void) +{ + ToolkitTestApplication application; + + auto check_box_button = Toolkit::CheckBoxButton::New(); + //check_box_button.SetLabelText( "button" ); + check_box_button.SetProperty(Toolkit::Button::Property::LABEL, "button"); + auto q = Dali::Accessibility::Accessible::Get( check_box_button ); + DALI_TEST_CHECK( q ); + DALI_TEST_EQUALS( q->GetName(), "button", TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp new file mode 100644 index 0000000..c68e84f --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls-BridgeUp.cpp @@ -0,0 +1,923 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Dali::Toolkit; + +void utc_dali_accessibility_controls_bridge_up_startup(void) +{ + test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); +} + +void utc_dali_accessibility_controls_bridge_up_cleanup(void) +{ + test_return_value = TET_PASS; + //DBusWrapper::Install({}) is a de-install + DBusWrapper::Install({}); +} + +namespace Dali { + namespace Accessibility { + std::ostream & operator<< (std::ostream & stream, const Address & address) + { + stream << address.ToString(); + return stream; + } + } +} + +int UtcDaliControlAccessibilityRaiseBridge(void) +{ + DALI_TEST_CHECK(!Accessibility::IsUp()); + + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC(true); + + DALI_TEST_CHECK(Accessibility::IsUp()); + + // auto wr = static_cast(DBusWrapper::Installed()); + // for(auto &a : wr->daliMethods) { + // const char *mt; + // if (std::get<3>(a.first) == MethodType::Method) mt = "MethodType::Method"; + // else if (std::get<3>(a.first) == MethodType::Getter) mt = "MethodType::Getter"; + // else if (std::get<3>(a.first) == MethodType::Setter) mt = "MethodType::Setter"; + // else assert(0); + // printf("%s %s %s %s\n", std::get<0>(a.first).c_str(), std::get<1>(a.first).c_str(), std::get<2>(a.first).c_str(), mt); + // } + + Dali::Accessibility::TestEnableSC(false); + + DALI_TEST_CHECK(!Accessibility::IsUp()); + + END_TEST; +} + +int UtcDaliControlAccessibilityName(void) +{ + ToolkitTestApplication application; + + auto control = Control::New(); + Stage::GetCurrent().Add( control ); + + auto q = Dali::Accessibility::Accessible::Get( control ); + DALI_TEST_CHECK( q ); + + DALI_TEST_EQUALS( "" , q->GetName(), TEST_LOCATION ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_NAME, "Accessibility_Name" ); + DALI_TEST_EQUALS( "Accessibility_Name" , q->GetName(), TEST_LOCATION ); + DALI_TEST_EQUALS( control.GetProperty( DevelControl::Property::ACCESSIBILITY_NAME ).Get< std::string >() , "Accessibility_Name", TEST_LOCATION ); + + DevelControl::AccessibilityGetNameSignal(control).Connect( [] (std::string &accessibility_name) { + accessibility_name = "Accessibility_Name_With_Callback"; } ); + + DALI_TEST_EQUALS( "Accessibility_Name_With_Callback" , q->GetName(), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC(true); + + DALI_TEST_EQUALS( "Accessibility_Name_With_Callback" , TestGetName( q->GetAddress()), TEST_LOCATION ); + + //TODO test emission of name change signal + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityDescription(void) +{ + ToolkitTestApplication application; + + auto control = Control::New(); + + auto q = Dali::Accessibility::Accessible::Get( control ); + DALI_TEST_CHECK( q ); + + DALI_TEST_EQUALS( "" , q->GetDescription(), TEST_LOCATION ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_DESCRIPTION, "Accessibility_Description" ); + DALI_TEST_EQUALS( "Accessibility_Description" , q->GetDescription(), TEST_LOCATION ); + + auto property = control.GetProperty( DevelControl::Property::ACCESSIBILITY_DESCRIPTION ).Get(); + DALI_TEST_EQUALS( "Accessibility_Description", property, TEST_LOCATION ); + + DevelControl::AccessibilityGetDescriptionSignal(control).Connect( [] (std::string &accessibility_description) { + accessibility_description = "Accessibility_Description_With_Callback"; } ); + + DALI_TEST_EQUALS( "Accessibility_Description_With_Callback" , q->GetDescription(), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + + DALI_TEST_EQUALS( "Accessibility_Description_With_Callback" , TestGetDescription( q->GetAddress()), TEST_LOCATION ); + + //TODO test emission of description change signal + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityRole(void) +{ + ToolkitTestApplication application; + + auto control = Control::New(); + auto role_unknown = Dali::Accessibility::Role::UNKNOWN; + auto role_pushbutton = Dali::Accessibility::Role::PUSH_BUTTON; + + DALI_TEST_EQUALS( role_unknown,control.GetProperty( DevelControl::Property::ACCESSIBILITY_ROLE ).Get< Dali::Accessibility::Role >(), TEST_LOCATION ); + + auto q = Dali::Accessibility::Accessible::Get( control ); + DALI_TEST_EQUALS( role_unknown , q->GetRole(), TEST_LOCATION); + DALI_TEST_EQUALS( "unknown" , q->GetRoleName(), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + DALI_TEST_CHECK( q ); + DALI_TEST_EQUALS( static_cast< uint32_t >( role_unknown ), TestGetRole( q->GetAddress() ), TEST_LOCATION ); + DALI_TEST_EQUALS( "unknown" , TestGetRoleName( q->GetAddress() ), TEST_LOCATION ); + DALI_TEST_EQUALS( "unknown" , TestGetLocalizedRoleName( q->GetAddress() ), TEST_LOCATION ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_ROLE, role_pushbutton ); + + DALI_TEST_EQUALS( static_cast< uint32_t >( role_pushbutton ), TestGetRole( q->GetAddress() ), TEST_LOCATION ); + DALI_TEST_EQUALS( "push button" ,TestGetRoleName( q->GetAddress() ), TEST_LOCATION ); + DALI_TEST_EQUALS( "push button" , TestGetLocalizedRoleName( q->GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + DALI_TEST_EQUALS( role_pushbutton , q->GetRole(), TEST_LOCATION); + DALI_TEST_EQUALS( "push button" , q->GetRoleName(), TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliControlAccessibilityRoleToggleButton(void) +{ + ToolkitTestApplication application; + + auto control = Dali::Toolkit::ToggleButton::New(); + auto button = Dali::Accessibility::Role::TOGGLE_BUTTON; + + control.SetProperty(Toolkit::ToggleButton::Property::TOOLTIPS, + Property::Array{"option1", "option2"}); + + Dali::Accessibility::TestEnableSC( true ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_ROLE, button ); + auto q = Dali::Accessibility::Accessible::Get( control ); + + DALI_TEST_EQUALS( button , q->GetRole(), TEST_LOCATION); + DALI_TEST_EQUALS( "toggle button" , q->GetRoleName(), TEST_LOCATION ); + + Dali::Accessibility::States states = q->GetStates(); + DALI_TEST_EQUALS( true , (bool)states[Dali::Accessibility::State::VISIBLE], TEST_LOCATION); + + DALI_TEST_EQUALS( "option1", q->GetDescription(), TEST_LOCATION ); + + auto i = dynamic_cast(q); + if (i) + i->GrabHighlight(); + + control.SetProperty( Toolkit::Button::Property::LABEL, "ToggleButton2" ); + DALI_TEST_EQUALS( "ToggleButton2", TestGetName( q->GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityButtonLabel(void) +{ + ToolkitTestApplication application; + + auto control = Dali::Toolkit::PushButton::New(); + auto button = Dali::Accessibility::Role::PUSH_BUTTON; + + Dali::Accessibility::TestEnableSC( true ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_ROLE, button ); + + auto q = Dali::Accessibility::Accessible::Get( control ); + auto i = dynamic_cast(q); + + if (i) + i->GrabHighlight(); + + control.SetProperty( Toolkit::Button::Property::LABEL, "Button2" ); + + DALI_TEST_EQUALS( "Button2" , TestGetName( q->GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityState(void) +{ + ToolkitTestApplication application; + + auto control = Control::New(); + auto q = Dali::Accessibility::Accessible::Get( control ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states_by_bridge = Dali::Accessibility::States { TestGetStates( q->GetAddress() )}; + auto states = DevelControl::GetAccessibilityStates(control); + DALI_TEST_CHECK( states_by_bridge == states ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityModal(void) +{ + ToolkitTestApplication application; + + auto control = Dali::Toolkit::Popup::New(); + auto q = Dali::Accessibility::Accessible::Get( control ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states_by_bridge = Dali::Accessibility::States { TestGetStates( q->GetAddress() )}; + DALI_TEST_CHECK( states_by_bridge[Dali::Accessibility::State::MODAL] ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityHighlightable(void) +{ + ToolkitTestApplication application; + auto control = Control::New(); + + auto noneset = control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ); + DALI_TEST_EQUALS( Property::NONE, noneset.GetType(), TEST_LOCATION ); + + // negative testcase - trying to set unconvertible value + control.SetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, "deadbeef" ); + noneset = control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ); + DALI_TEST_EQUALS( Property::NONE, noneset.GetType(), TEST_LOCATION ); + + auto q = Dali::Accessibility::Accessible::Get( control ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states_by_bridge = Dali::Accessibility::States { TestGetStates( q->GetAddress() )}; + DALI_TEST_CHECK( !states_by_bridge[ Dali::Accessibility::State::HIGHLIGHTABLE ] ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + DALI_TEST_EQUALS( Property::BOOLEAN, control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).GetType(), TEST_LOCATION ); + DALI_TEST_EQUALS( true, control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).Get< bool >(), TEST_LOCATION ); + + states_by_bridge = Dali::Accessibility::States { TestGetStates( q->GetAddress() )}; + DALI_TEST_CHECK( states_by_bridge[ Dali::Accessibility::State::HIGHLIGHTABLE ] ); + + control.SetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false ); + DALI_TEST_EQUALS( Property::BOOLEAN, control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).GetType(), TEST_LOCATION ); + DALI_TEST_EQUALS( false, control.GetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).Get< bool >(), TEST_LOCATION ); + + states_by_bridge = Dali::Accessibility::States { TestGetStates( q->GetAddress() )}; + DALI_TEST_CHECK( !states_by_bridge[ Dali::Accessibility::State::HIGHLIGHTABLE ] ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlAccessibilityHighlightBridgeUp(void) +{ + ToolkitTestApplication application; + + auto controla = Control::New(); + auto controlb = Control::New(); + controla.Add(controlb); + + controla.SetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + controlb.SetProperty( DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + + Dali::Accessibility::TestEnableSC( true ); + + auto accessible_a = Dali::Accessibility::Accessible::Get( controla ); + auto accessible_b = Dali::Accessibility::Accessible::Get( controlb ); + + auto a = dynamic_cast( accessible_a ); + auto b = dynamic_cast( accessible_b ); + + auto states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + auto states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_EQUALS( true, DevelControl::GrabAccessibilityHighlight(controla), TEST_LOCATION ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_EQUALS( true, DevelControl::GrabAccessibilityHighlight(controlb), TEST_LOCATION ); + DALI_TEST_EQUALS( true, DevelControl::GrabAccessibilityHighlight(controlb), TEST_LOCATION ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_EQUALS( false, DevelControl::ClearAccessibilityHighlight(controla), TEST_LOCATION ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_EQUALS( true, DevelControl::ClearAccessibilityHighlight(controlb), TEST_LOCATION ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_CHECK( TestGrabHighlight( a -> GetAddress() ) ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_CHECK( TestGrabHighlight( b -> GetAddress() ) ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + DALI_TEST_CHECK( TestClearHighlight( b -> GetAddress() ) ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a->GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b->GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::HIGHLIGHTED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::HIGHLIGHTED ] ); + + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int utcDaliAccessibilityControlAttributes(void) +{ + ToolkitTestApplication application; + auto check_box_button = Toolkit::Control::New(); + + std::string value; + + + auto attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + auto attributes_map = attributes.GetMap(); + + auto position = attributes_map->Find( "access_key1" ); + DALI_TEST_CHECK( !position ); + + DevelControl::AppendAccessibilityAttribute( check_box_button, "access_key1", "access_value1" ); + attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + attributes_map = attributes.GetMap(); + + DALI_TEST_EQUALS( (attributes_map->Find( "access_key1" ))->Get(), "access_value1", TEST_LOCATION ); + + DevelControl::AppendAccessibilityAttribute( check_box_button, "access_key2", "access_value2_a" ); + attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + attributes_map = attributes.GetMap(); + + DALI_TEST_EQUALS( (attributes_map->Find( "access_key1" ))->Get(), "access_value1", TEST_LOCATION ); + DALI_TEST_EQUALS( (attributes_map->Find( "access_key2" ))->Get(), "access_value2_a", TEST_LOCATION ); + + DevelControl::AppendAccessibilityAttribute( check_box_button, "access_key2", "access_value2_b" ); + attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + attributes_map = attributes.GetMap(); + + DALI_TEST_EQUALS( (attributes_map->Find( "access_key2" ))->Get(), "access_value2_b", TEST_LOCATION ); + + DevelControl::RemoveAccessibilityAttribute( check_box_button, "access_key2" ); + attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + attributes_map = attributes.GetMap(); + + // In case when we are removing one of attributes the property is setting for NONE type. + DALI_TEST_EQUALS( (attributes_map->Find( "access_key2" ))->GetType(), Property::NONE, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + + auto ptr = Dali::Accessibility::Accessible::Get( check_box_button ); + auto attribute_map_bridge = TestGetAttributes( ptr->GetAddress() ); + auto counter = 0u; + for (auto i = 0u; iCount();++i) + if((attributes_map->GetValue(i)).GetType() != Property::NONE ) + ++counter; + + DALI_TEST_EQUALS( counter, attribute_map_bridge.size(), TEST_LOCATION ); + + for (auto it : attribute_map_bridge) + DALI_TEST_EQUALS( (attributes_map->Find( it.first ))->Get(), it.second, TEST_LOCATION ); + + DevelControl::ClearAccessibilityAttributes(check_box_button); + attributes = check_box_button.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + attributes_map = attributes.GetMap(); + + position = attributes_map->Find( "access_key1" ); + DALI_TEST_CHECK( !position ); + + position = attributes_map->Find( "access_key2" ); + DALI_TEST_CHECK( !position ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliControlReadingInfoType(void) +{ + ToolkitTestApplication application; + auto control = Control::New(); + + auto reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control); + reading_info_type[Dali::Accessibility::ReadingInfoType::DESCRIPTION] = true; + reading_info_type[Dali::Accessibility::ReadingInfoType::STATE] = true; + reading_info_type[Dali::Accessibility::ReadingInfoType::NAME] = true; + reading_info_type[Dali::Accessibility::ReadingInfoType::ROLE] = true; + + DevelControl::SetAccessibilityReadingInfoType(control, reading_info_type); + + auto q = control.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + auto z = q.GetMap(); + + DALI_TEST_EQUALS( (z->Find( "reading_info_type" ))->Get(), "name|role|description|state", TEST_LOCATION ); + reading_info_type = DevelControl::GetAccessibilityReadingInfoType(control); + for ( auto i = 0u; i < 4; ++i) + DALI_TEST_CHECK ( reading_info_type[ static_cast< Dali::Accessibility::ReadingInfoType >( i ) ]); + + END_TEST; +} + +int UtcDaliControlDoGesture(void) +{ + ToolkitTestApplication application; + auto control = Control::New(); + Dali::Accessibility::TestEnableSC( true ); + + auto accessible = Dali::Accessibility::Accessible::Get( control ); + auto gesture_one = Dali::Accessibility::GestureInfo { Dali::Accessibility::Gesture::ONE_FINGER_FLICK_LEFT, 600, 100, 500, 500, Dali::Accessibility::GestureState::BEGIN, 1000 }; + auto gesture_two = Dali::Accessibility::GestureInfo { Dali::Accessibility::Gesture::ONE_FINGER_FLICK_RIGHT, 600, 100, 500, 500, Dali::Accessibility::GestureState::BEGIN, 1000 }; + + DALI_TEST_CHECK( !accessible->DoGesture( gesture_one ) ); + DALI_TEST_CHECK( !TestDoGesture( accessible->GetAddress(), Dali::Accessibility::Gesture::ONE_FINGER_FLICK_LEFT, 600, 100, 500, 500, Dali::Accessibility::GestureState::BEGIN, 1000 ) ); + + DevelControl::AccessibilityDoGestureSignal(control).Connect( [] ( std::pair< Dali::Accessibility::GestureInfo, bool > &gesture ) { + if ( gesture.first.type == Dali::Accessibility::Gesture::ONE_FINGER_FLICK_LEFT ) + gesture.second = true; + else + gesture.second = false; + } ); + + DALI_TEST_CHECK( accessible->DoGesture( gesture_one ) ); + DALI_TEST_CHECK( TestDoGesture( accessible->GetAddress(), Dali::Accessibility::Gesture::ONE_FINGER_FLICK_LEFT, 600, 100, 500, 500, Dali::Accessibility::GestureState::BEGIN, 1000 ) ); + + DALI_TEST_CHECK( !accessible->DoGesture( gesture_two ) ); + DALI_TEST_CHECK( !TestDoGesture( accessible->GetAddress(), Dali::Accessibility::Gesture::ONE_FINGER_FLICK_RIGHT, 600, 100, 500, 500, Dali::Accessibility::GestureState::BEGIN, 1000 ) ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityRelation(void) +{ + ToolkitTestApplication application; + Dali::Accessibility::TestEnableSC( true ); + + auto rel = Accessibility::RelationType::FLOWS_TO; + auto number = static_cast< size_t >( rel ); + auto control = Control::New(); + auto destination1 = Control::New(); + auto destination2 = Control::New(); + + DevelControl::AppendAccessibilityRelation( control, destination1, rel ); + auto relations = DevelControl::GetAccessibilityRelations(control); + DALI_TEST_CHECK( relations[ number ].size() == 1 ); + + DevelControl::AppendAccessibilityRelation( control, destination2, rel ); + relations = DevelControl::GetAccessibilityRelations(control); + DALI_TEST_CHECK( relations[ number ].size() == 2 ); + + auto accessible = Dali::Accessibility::Accessible::Get( control ); + auto accessible_destination1 = Dali::Accessibility::Accessible::Get( destination1 ); + auto accessible_destination2 = Dali::Accessibility::Accessible::Get( destination2 ); + auto relationset = accessible->GetRelationSet(); + + DALI_TEST_CHECK( relationset[0].relationType == rel ); + DALI_TEST_CHECK( relationset[0].targets[0] == accessible_destination1->GetAddress() || relationset[0].targets[1] == accessible_destination1->GetAddress() ); + DALI_TEST_CHECK( relationset[0].targets[0] == accessible_destination2->GetAddress() || relationset[0].targets[1] == accessible_destination2->GetAddress() ); + + auto relationset_bridge = TestGetRelationSet( accessible -> GetAddress() ); + DALI_TEST_CHECK( static_cast< uint32_t >( relationset[0].relationType ) == std::get<0>( relationset_bridge[0] ) ); + + DALI_TEST_CHECK( relationset[0].targets[0] == std::get<1>( relationset_bridge[0] )[0] || relationset[0].targets[1] == std::get<1>( relationset_bridge[0] )[0] ); + DALI_TEST_CHECK( relationset[0].targets[0] == std::get<1>( relationset_bridge[0] )[1] || relationset[0].targets[1] == std::get<1>( relationset_bridge[0] )[1] ); + + DevelControl::RemoveAccessibilityRelation(control,destination2,rel); + relations = DevelControl::GetAccessibilityRelations(control); + DALI_TEST_CHECK( relations[ number ].size() == 1 ); + + DevelControl::ClearAccessibilityRelations(control); + relations = DevelControl::GetAccessibilityRelations(control); + DALI_TEST_CHECK( relations[ number ].size() == 0 ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityParentChildren(void) +{ + ToolkitTestApplication application; + Dali::Accessibility::TestEnableSC( true ); + + auto parent = Control::New(); + auto child_1 = Control::New(); + auto child_2 = Control::New(); + + auto parent_accessible = Dali::Accessibility::Accessible::Get( parent ); + auto child_1_accessible = Dali::Accessibility::Accessible::Get( child_1 ); + auto child_2_accessible = Dali::Accessibility::Accessible::Get( child_2 ); + + auto children = TestGetChildren( parent_accessible -> GetAddress() ); + DALI_TEST_EQUALS( children.size(), 0, TEST_LOCATION ); + + try + { + TestGetIndexInParent( child_1_accessible -> GetAddress() ); + DALI_ABORT("Object has parent, test abort"); + } + catch(TestDBusWrapper::error &){} + + try + { + TestGetChildAtIndex( parent_accessible -> GetAddress(), -1 ); + DALI_ABORT("Positive index, test abort"); + } + catch(TestDBusWrapper::error &){} + + DALI_TEST_EQUALS( parent_accessible -> GetChildCount(), 0, TEST_LOCATION ); + + try + { + child_1_accessible -> GetIndexInParent(); + DALI_ABORT("Object has parent, test abort"); + } + catch (Dali::DaliException &){} + + parent.Add(child_1); + parent.Add(child_2); + + children = TestGetChildren( parent_accessible -> GetAddress() ); + DALI_TEST_EQUALS( children.size(), 2, TEST_LOCATION ); + + DALI_TEST_EQUALS( parent_accessible -> GetAddress(), TestGetParent( child_1_accessible -> GetAddress() ), TEST_LOCATION ); + DALI_TEST_EQUALS( child_2_accessible -> GetAddress(), TestGetChildAtIndex( parent_accessible -> GetAddress(), TestGetIndexInParent( child_2_accessible -> GetAddress() ) ), TEST_LOCATION ); + + DALI_TEST_EQUALS( parent_accessible, child_1_accessible -> GetParent(), TEST_LOCATION ); + DALI_TEST_EQUALS( child_2_accessible, parent_accessible -> GetChildAtIndex( child_2_accessible -> GetIndexInParent() ) , TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityGetLayer(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto control = Control::New(); + auto accessible_obj = Dali::Accessibility::Accessible::Get( control ); + auto accessible_component = dynamic_cast(accessible_obj); + DALI_TEST_CHECK( accessible_component ); + DALI_TEST_EQUALS( Dali::Accessibility::ComponentLayer::WINDOW, accessible_component -> GetLayer(), TEST_LOCATION ); + DALI_TEST_EQUALS( Dali::Accessibility::ComponentLayer::WINDOW, TestGetLayer( accessible_component -> GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityGrabFocus(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto controla = Control::New(); + auto controlb = Control::New(); + + Stage::GetCurrent().Add( controla ); + Stage::GetCurrent().Add( controlb ); + + controla.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); + controlb.SetProperty(Actor::Property::KEYBOARD_FOCUSABLE, true); + + auto a = Dali::Accessibility::Accessible::Get( controla ); + auto b = Dali::Accessibility::Accessible::Get( controlb ); + + auto a_component = dynamic_cast( a ); + auto b_component = dynamic_cast( b ); + + auto states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a_component -> GetAddress() )}; + auto states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b_component -> GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::FOCUSED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::FOCUSED ] ); + + DALI_TEST_CHECK( a_component -> GrabFocus() ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a_component -> GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b_component -> GetAddress() )}; + + DALI_TEST_CHECK( states_by_bridge_a[ Dali::Accessibility::State::FOCUSED ] ); + DALI_TEST_CHECK( !states_by_bridge_b[ Dali::Accessibility::State::FOCUSED ] ); + + DALI_TEST_CHECK( TestGrabFocus( b_component -> GetAddress() ) ); + + states_by_bridge_a = Dali::Accessibility::States { TestGetStates( a_component -> GetAddress() )}; + states_by_bridge_b = Dali::Accessibility::States { TestGetStates( b_component -> GetAddress() )}; + + DALI_TEST_CHECK( !states_by_bridge_a[ Dali::Accessibility::State::FOCUSED ] ); + DALI_TEST_CHECK( states_by_bridge_b[ Dali::Accessibility::State::FOCUSED ] ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityGetExtents(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto control = Control::New(); + Stage::GetCurrent().GetRootLayer().Add( control ); + + control.SetProperty(Actor::Property::POSITION, Vector3(10, 10, 100)); + control.SetProperty(Actor::Property::SIZE, Vector2(10, 10)); + + application.SendNotification(); + application.Render( 1 ); + + auto a = Dali::Accessibility::Accessible::Get( control ); + auto a_component = dynamic_cast( a ); + + auto extents = a_component->GetExtents(Dali::Accessibility::CoordType::SCREEN); + DALI_TEST_EQUALS( extents.x, 5.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.y, 5.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.height, 10.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.width, 10.0f, TEST_LOCATION ); + + auto bridge_extents = TestGetExtents( a_component -> GetAddress() ); + DALI_TEST_EQUALS( std::get< 0 >( bridge_extents ), 5, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 1 >( bridge_extents ), 5, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 2 >( bridge_extents ), 10, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 3 >( bridge_extents ), 10, TEST_LOCATION ); + + control.SetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT, false ); + application.SendNotification(); + application.Render( 1 ); + + extents = a_component->GetExtents(Dali::Accessibility::CoordType::SCREEN); + DALI_TEST_EQUALS( extents.x, 10.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.y, 10.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.height, 10.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( extents.width, 10.0f, TEST_LOCATION ); + + bridge_extents = TestGetExtents( a_component -> GetAddress() ); + DALI_TEST_EQUALS( std::get< 0 >( bridge_extents ), 10, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 1 >( bridge_extents ), 10, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 2 >( bridge_extents ), 10, TEST_LOCATION ); + DALI_TEST_EQUALS( std::get< 3 >( bridge_extents ), 10, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityGetAlpha(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto control = Control::New(); + auto a = Dali::Accessibility::Accessible::Get( control ); + auto a_component = dynamic_cast( a ); + + DALI_TEST_EQUALS( 0.0, a_component -> GetAlpha(), TEST_LOCATION ); + DALI_TEST_EQUALS( 0.0, TestGetAlpha( a_component -> GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityGetMdiZOrder(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto control = Control::New(); + auto a = Dali::Accessibility::Accessible::Get( control ); + auto a_component = dynamic_cast( a ); + + DALI_TEST_EQUALS( 0, static_cast< int >( a_component -> GetMdiZOrder() ), TEST_LOCATION ); + DALI_TEST_EQUALS( 0, TestGetMdiZOrder( a_component -> GetAddress() ), TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityAction(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + + auto control = Control::New( ); + auto a = Dali::Accessibility::Accessible::Get( control ); + auto b = dynamic_cast( a ); + + std::vector< std::string > actions { "activate", "accessibilityActivated", "ReadingSkipped", "ReadingCancelled", "ReadingStopped", "ReadingPaused", "ReadingResumed", "show", "hide" }; + auto count = b -> GetActionCount(); + + DALI_TEST_EQUALS( count, 9, TEST_LOCATION ); + + for (auto i = 0u; i GetActionName( i ) ) ); + DALI_TEST_EQUALS( b -> GetActionName( i ), b -> GetLocalizedActionName( i ), TEST_LOCATION ); + DALI_TEST_EQUALS( b -> GetActionDescription( i ), "", TEST_LOCATION ); + DALI_TEST_EQUALS( b -> GetActionKeyBinding( i ), "", TEST_LOCATION ); + } + + // Empty strings should be returned for invalid indices + DALI_TEST_EQUALS(b->GetActionDescription(count), "", TEST_LOCATION); + DALI_TEST_EQUALS(b->GetActionName(count), "", TEST_LOCATION); + DALI_TEST_EQUALS(b->GetLocalizedActionName(count), "", TEST_LOCATION); + DALI_TEST_EQUALS(b->GetActionKeyBinding(count), "", TEST_LOCATION); + + count = TestGetActionCount(b -> GetAddress()); + + DALI_TEST_EQUALS( count, 9, TEST_LOCATION ); + + for (auto i = 0u; iGetAddress(), i ) ) ); + DALI_TEST_EQUALS( TestGetActionName( b->GetAddress(), i ), TestGetLocalizedActionName( b->GetAddress(), i ), TEST_LOCATION ); + DALI_TEST_EQUALS( TestGetActionDescription( b->GetAddress(), i ), "", TEST_LOCATION ); + DALI_TEST_EQUALS( TestGetActionKeyBinding( b->GetAddress(), i ), "", TEST_LOCATION ); + } + + DALI_TEST_EQUALS(TestGetActionDescription(b->GetAddress(), count), "", TEST_LOCATION); + DALI_TEST_EQUALS(TestGetActionName(b->GetAddress(), count), "", TEST_LOCATION); + DALI_TEST_EQUALS(TestGetLocalizedActionName(b->GetAddress(), count), "", TEST_LOCATION); + DALI_TEST_EQUALS(TestGetActionKeyBinding(b->GetAddress(), count), "", TEST_LOCATION); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityDoAction(void) +{ + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC( true ); + thread_local std::vector< bool > actions_done { false, false, false, false, false, false }; + + auto control = Control::New( ); + auto a = Dali::Accessibility::Accessible::Get( control ); + auto b = dynamic_cast( a ); + std::vector< std::string > actions { "activate", "accessibilityActivated", "ReadingSkipped", "ReadingCancelled", "ReadingStopped", "ReadingPaused", "ReadingResumed", "show", "hide" }; + + // Test calling action by name + DALI_TEST_CHECK( b -> DoAction( actions[2] ) ); // ReadingSkipped + DALI_TEST_CHECK( b -> DoAction( actions[4] ) ); // ReadingStopped + DALI_TEST_CHECK( b -> DoAction( actions[4] ) ); // ReadingStopped + + // Negative test of calling action with not defined name + DALI_TEST_CHECK( !b -> DoAction( "undefined" ) ); + + DevelControl::AccessibilityReadingSkippedSignal(control).Connect( [] () { + actions_done[ 1 ] = true; + } ); + DevelControl::AccessibilityReadingCancelledSignal(control).Connect( [] () { + actions_done[ 2 ] = true; + } ); + DevelControl::AccessibilityReadingStoppedSignal(control).Connect( [] () { + actions_done[ 3 ] = true; + } ); + DevelControl::AccessibilityReadingPausedSignal(control).Connect( [] () { + actions_done[ 4 ] = true; + } ); + DevelControl::AccessibilityReadingResumedSignal(control).Connect( [] () { + actions_done[ 5 ] = true; + } ); + DevelControl::AccessibilityActivateSignal(control).Connect( [] () { + actions_done[ 0 ] = true; + } ); + + // Test calling action by index + DALI_TEST_CHECK( b -> DoAction( 1 ) ); + DALI_TEST_CHECK( b -> DoAction( 2 ) ); + DALI_TEST_CHECK( b -> DoAction( 3 ) ); + DALI_TEST_CHECK( b -> DoAction( 4 ) ); + DALI_TEST_CHECK( b -> DoAction( 5 ) ); + DALI_TEST_CHECK( b -> DoAction( 6 ) ); + + for ( auto i = 0u; i < actions_done.size(); ++i ) + { + DALI_TEST_CHECK( actions_done[ i ] ); + actions_done[ i ] = false; + } + + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 1 ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 2 ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 3 ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 4 ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 5 ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), 6 ) ); + + for ( auto i = 0u; i < actions_done.size(); ++i ) + { + DALI_TEST_CHECK( actions_done[ i ] ); + actions_done[ i ] = false; + } + + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 1 ] ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 2 ] ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 3 ] ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 4 ] ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 5 ] ) ); + DALI_TEST_CHECK( TestDoAction( b -> GetAddress(), actions[ 6 ] ) ); + + for ( auto i = 0u; i < actions_done.size(); ++i ) + DALI_TEST_CHECK( actions_done[ i ] ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +void TestVoidCallback() +{ +} + +int UtcDaliAccessibilitySignals(void) +{ + ToolkitTestApplication application; + ConnectionTracker connectionTracker; + Control control = Control::New(); + + DALI_TEST_CHECK( DevelControl::AccessibilityGetNameSignal(control).Empty() ); + control.ConnectSignal( &connectionTracker, "getName", &TestVoidCallback ); + DALI_TEST_CHECK( !DevelControl::AccessibilityGetNameSignal(control).Empty() ); + + DALI_TEST_CHECK( DevelControl::AccessibilityGetDescriptionSignal(control).Empty() ); + control.ConnectSignal( &connectionTracker, "getDescription", &TestVoidCallback ); + DALI_TEST_CHECK( !DevelControl::AccessibilityGetDescriptionSignal(control).Empty() ); + + DALI_TEST_CHECK( DevelControl::AccessibilityDoGestureSignal(control).Empty() ); + control.ConnectSignal( &connectionTracker, "doGesture", &TestVoidCallback ); + DALI_TEST_CHECK( !DevelControl::AccessibilityDoGestureSignal(control).Empty() ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls.cpp new file mode 100644 index 0000000..bd8f3a4 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Controls.cpp @@ -0,0 +1,677 @@ +#include +#include +#include + +#include +#include +#include + +#include + +using namespace Dali::Toolkit; + +void utc_dali_accessibility_controls_startup(void) +{ + test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); +} + +void utc_dali_accessibility_controls_cleanup(void) +{ + test_return_value = TET_PASS; + //DBusWrapper::Install({}) is a de-install + DBusWrapper::Install({}); +} + +int UtcDaliControlPropertyAccessibilityTranslationDomain(void) +{ + ToolkitTestApplication application; + + auto control = Control::New(); + + auto accessibility_translation_domain = DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN; + DALI_TEST_EQUALS( Property::NONE , control.GetProperty( accessibility_translation_domain ).GetType(), TEST_LOCATION ); + + control.SetProperty( accessibility_translation_domain, "translation_domain_test_1" ); + DALI_TEST_EQUALS( "translation_domain_test_1" , control.GetProperty( accessibility_translation_domain ).Get< std::string >(), TEST_LOCATION ); + + control.SetProperty( accessibility_translation_domain, "translation_domain_test_2" ); + DALI_TEST_EQUALS( "translation_domain_test_2" , control.GetProperty( accessibility_translation_domain ).Get< std::string >(), TEST_LOCATION ); + + END_TEST; +} + +// This test shows that when the accessibility bridge is +// not up, there is no possibility to grab or clear highlight +int UtcDaliControlAccessibilityHighlight(void) +{ + ToolkitTestApplication application; + auto controla = Control::New(); + auto controlb = Control::New(); + + DALI_TEST_EQUALS( false, DevelControl::GrabAccessibilityHighlight(controla), TEST_LOCATION ); + DALI_TEST_EQUALS( false, DevelControl::GrabAccessibilityHighlight(controlb), TEST_LOCATION ); + DALI_TEST_EQUALS( false, DevelControl::ClearAccessibilityHighlight(controla), TEST_LOCATION ); + DALI_TEST_EQUALS( false, DevelControl::ClearAccessibilityHighlight(controlb), TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityToolBarConstructor(void) +{ + ToolkitTestApplication application; + + auto toolbar = ToolBar::New(); + DALI_TEST_CHECK( toolbar ); + + auto accessible = Dali::Accessibility::Accessible::Get( toolbar ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::TOOL_BAR, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityPushButtonConstructor(void) +{ + ToolkitTestApplication application; + + auto pushbutton = PushButton::New(); + DALI_TEST_CHECK( pushbutton ); + + auto accessible = Dali::Accessibility::Accessible::Get( pushbutton ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::PUSH_BUTTON, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityPushButtonStates(void) +{ + ToolkitTestApplication application; + + auto pushbutton = PushButton::New(); + DALI_TEST_CHECK( pushbutton ); + + auto accessible = Dali::Accessibility::Accessible::Get( pushbutton ); + DALI_TEST_CHECK( accessible ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::PRESSED ] ), false, TEST_LOCATION ); + + // auto button = dynamic_cast( accessible ) ; + pushbutton.SetProperty( Toolkit::Button::Property::TOGGLABLE, true ); + pushbutton.SetProperty( Toolkit::Button::Property::SELECTED, true ); + + states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::PRESSED ] ), true, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityToggleButtonConstructor(void) +{ + ToolkitTestApplication application; + + auto togglebutton = ToggleButton::New(); + DALI_TEST_CHECK( togglebutton ); + + auto accessible = Dali::Accessibility::Accessible::Get( togglebutton ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::TOGGLE_BUTTON, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityTextSelectionPopupConstructor(void) +{ + ToolkitTestApplication application; + + auto textselectionpopup = TextSelectionPopup::New( NULL ); + DALI_TEST_CHECK( textselectionpopup ); + + auto accessible = Dali::Accessibility::Accessible::Get( textselectionpopup ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::DIALOG, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityAlignmentConstructor(void) +{ + ToolkitTestApplication application; + + auto alignment = Alignment::New(); + DALI_TEST_CHECK( alignment ); + + auto accessible = Dali::Accessibility::Accessible::Get( alignment ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityRadioButtonStates(void) +{ + ToolkitTestApplication application; + + auto radiobutton = RadioButton::New(); + DALI_TEST_CHECK( radiobutton ); + + auto accessible = Dali::Accessibility::Accessible::Get( radiobutton ); + DALI_TEST_CHECK( accessible ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states = accessible->GetStates(); + DALI_TEST_CHECK( states ); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::CHECKED ] ), false, TEST_LOCATION ); + radiobutton.SetProperty( Toolkit::RadioButton::Property::SELECTED, true ); + states = accessible->GetStates(); + DALI_TEST_CHECK( states ); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::CHECKED ] ), true, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityFlexContainerConstructor(void) +{ + ToolkitTestApplication application; + + auto flexcontainer = FlexContainer::New(); + DALI_TEST_CHECK( flexcontainer ); + + auto accessible = Dali::Accessibility::Accessible::Get( flexcontainer ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityCheckBoxButton(void) +{ + ToolkitTestApplication application; + + auto checkboxbutton = CheckBoxButton::New(); + DALI_TEST_CHECK( checkboxbutton ); + + auto accessible = Dali::Accessibility::Accessible::Get( checkboxbutton ); + DALI_TEST_CHECK( accessible ); + + Dali::Accessibility::TestEnableSC( true ); + + auto states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::CHECKED ] ), false, TEST_LOCATION ); + checkboxbutton.SetProperty( Toolkit::CheckBoxButton::Property::SELECTED, true ); + states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::CHECKED ] ), true, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityTextSelectionConstructor(void) +{ + ToolkitTestApplication application; + + auto textselectiontoolbar = TextSelectionToolbar::New(); + DALI_TEST_CHECK( textselectiontoolbar ); + + auto accessible = Dali::Accessibility::Accessible::Get( textselectiontoolbar ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::TOOL_BAR, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityManager(void) +{ + using attr = Toolkit::AccessibilityManager::AccessibilityAttribute; + + ToolkitTestApplication application; + + Dali::Accessibility::TestEnableSC(true); + + auto accessmanager = new Dali::Toolkit::Internal::AccessibilityManager; + auto actor = Control::New(); + + const std::string name = "Name"; + const std::string descr = "Description"; + + accessmanager->SetAccessibilityAttribute(actor, attr::ACCESSIBILITY_LABEL, name); + DALI_TEST_EQUALS( accessmanager->GetAccessibilityAttribute(actor, attr::ACCESSIBILITY_LABEL), name, TEST_LOCATION ); + DALI_TEST_EQUALS( actor.GetProperty(DevelControl::Property::ACCESSIBILITY_NAME), name, TEST_LOCATION ); + + accessmanager->SetAccessibilityAttribute(actor, attr::ACCESSIBILITY_TRAIT, "Whatever"); + DALI_TEST_EQUALS( accessmanager->GetAccessibilityAttribute(actor, attr::ACCESSIBILITY_TRAIT), "", TEST_LOCATION ); + + accessmanager->SetAccessibilityAttribute(actor, attr::ACCESSIBILITY_VALUE, "Whatever"); + DALI_TEST_EQUALS( accessmanager->GetAccessibilityAttribute(actor, attr::ACCESSIBILITY_VALUE), "", TEST_LOCATION ); + + accessmanager->SetAccessibilityAttribute(actor, attr::ACCESSIBILITY_HINT, descr); + DALI_TEST_EQUALS( accessmanager->GetAccessibilityAttribute(actor, attr::ACCESSIBILITY_HINT), descr, TEST_LOCATION ); + DALI_TEST_EQUALS( actor.GetProperty(DevelControl::Property::ACCESSIBILITY_DESCRIPTION), descr, TEST_LOCATION ); + + DALI_TEST_EQUALS( accessmanager->GetFocusOrder(actor), 0, TEST_LOCATION ); + DALI_TEST_EQUALS( accessmanager->GenerateNewFocusOrder(), 1, TEST_LOCATION ); + + accessmanager->SetFocusOrder({}, 0); + accessmanager->SetFocusOrder(Control::New(), 1); + accessmanager->SetFocusOrder(actor, 2); + accessmanager->SetFocusOrder(Control::New(), 3); + + DALI_TEST_EQUALS( accessmanager->GetFocusOrder(actor), 2, TEST_LOCATION ); + DALI_TEST_EQUALS( accessmanager->GetActorByFocusOrder(2), actor, TEST_LOCATION ); + + accessmanager->SetCurrentFocusActor(actor); + DALI_TEST_EQUALS( accessmanager->GetCurrentFocusActor(), actor, TEST_LOCATION ); + DALI_TEST_EQUALS( accessmanager->GetCurrentFocusOrder(), 2, TEST_LOCATION ); + + accessmanager->MoveFocusForward(); + accessmanager->MoveFocusBackward(); + DALI_TEST_EQUALS( accessmanager->GetCurrentFocusActor(), actor, TEST_LOCATION ); + accessmanager->SetCurrentFocusActor({}); + + accessmanager->Reset(); + accessmanager->MoveFocusBackward(); + accessmanager->MoveFocusForward(); + + accessmanager->GetCurrentFocusGroup(); + DALI_TEST_EQUALS( accessmanager->IsFocusGroup(actor), false, TEST_LOCATION ); + accessmanager->GetFocusGroup(actor); + + DALI_TEST_EQUALS( accessmanager->GetGroupMode(), false, TEST_LOCATION ); + DALI_TEST_EQUALS( accessmanager->GetWrapMode(), true, TEST_LOCATION ); + + auto vector = accessmanager->GetReadPosition(); + DALI_TEST_EQUALS( vector.x, 0.0f, TEST_LOCATION ); + DALI_TEST_EQUALS( vector.y, 0.0f, TEST_LOCATION ); + + accessmanager->SetFocusIndicatorActor(Dali::Actor{}); + accessmanager->GetFocusIndicatorActor(); + + Dali::Accessibility::TestEnableSC(false); + + END_TEST; +} + +int UtcDaliAccessibilityModel3dViewConstructor(void) +{ + ToolkitTestApplication application; + + auto model3dview = Model3dView::New(); + DALI_TEST_CHECK( model3dview ); + + auto accessible = Dali::Accessibility::Accessible::Get( model3dview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::IMAGE, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityEffectsViewConstructor(void) +{ + ToolkitTestApplication application; + + auto etype = Dali::Toolkit::EffectsView::EffectType::DROP_SHADOW; + auto effectsview = EffectsView::New( etype ); + DALI_TEST_CHECK( effectsview ); + + auto accessible = Dali::Accessibility::Accessible::Get( effectsview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilitySuperBlurViewConstructor(void) +{ + ToolkitTestApplication application; + + auto superblurview = SuperBlurView::New( 1 ); + DALI_TEST_CHECK( superblurview ); + + auto accessible = Dali::Accessibility::Accessible::Get( superblurview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityImageViewConstructor(void) +{ + ToolkitTestApplication application; + + auto imageview = ImageView::New(); + DALI_TEST_CHECK( imageview ); + + auto accessible = Dali::Accessibility::Accessible::Get( imageview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::IMAGE, TEST_LOCATION ); + + END_TEST; +} + +#include +class TestPageFactory : public PageFactory +{ +public: + + TestPageFactory( bool returnValidTexture = true ) + : mValidTexture( returnValidTexture ) + { + mTotalPageNumber = 100; + } + + /** + * Query the number of pages available from the factory. + * The maximum available page has an ID of GetNumberOfPages()-1. + */ + virtual unsigned int GetNumberOfPages() + { + return mTotalPageNumber; + } + + /** + * Create an texture to represent a page content. + * @param[in] pageId The ID of the page to create. + * @return An image, or an empty handle if the ID is out of range. + */ + virtual Texture NewPage( unsigned int pageId ) + { + if( mValidTexture ) + { + return Texture::New( Dali::TextureType::TEXTURE_2D, Pixel::RGB888, 100, 100 ); + } + return Texture(); // empty handle + } + +private: + unsigned int mTotalPageNumber; + bool mValidTexture; +}; + +#include +int UtcDaliAccessibilityPageTurnViewConstructor(void) +{ + ToolkitTestApplication application; + + auto testpagefactory = TestPageFactory(); + auto vector2 = Vector2( 1.0, 1.0 ); + auto pageturnlandscapeview = PageTurnLandscapeView::New( testpagefactory, vector2 ); + DALI_TEST_CHECK( pageturnlandscapeview ); + + auto accessible = Dali::Accessibility::Accessible::Get( pageturnlandscapeview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::PAGE_TAB_LIST, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityGaussianBlurViewConstructor(void) +{ + ToolkitTestApplication application; + + auto gaussianblurview = GaussianBlurView::New(); + DALI_TEST_CHECK( gaussianblurview ); + + auto accessible = Dali::Accessibility::Accessible::Get( gaussianblurview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityShadowViewConstructor(void) +{ + ToolkitTestApplication application; + + auto shadowview = ShadowView::New(); + DALI_TEST_CHECK( shadowview ); + + auto accessible = Dali::Accessibility::Accessible::Get( shadowview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +#include +#include +int UtcDaliAccessibilityScrollableConstructor(void) +{ + ToolkitTestApplication application; + + auto scrollview = ScrollView::New(); + DALI_TEST_CHECK( scrollview ); + + auto accessible = Dali::Accessibility::Accessible::Get( scrollview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::SCROLL_PANE, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityMagnifierConstructor(void) +{ + ToolkitTestApplication application; + + auto magnifier = Magnifier::New(); + DALI_TEST_CHECK( magnifier ); + + auto accessible = Dali::Accessibility::Accessible::Get( magnifier ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityTableViewConstructor(void) +{ + ToolkitTestApplication application; + + auto tableview = TableView::New( 10, 10 ); + DALI_TEST_CHECK( tableview ); + + auto accessible = Dali::Accessibility::Accessible::Get( tableview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::TABLE, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityBloomViewConstructor(void) +{ + ToolkitTestApplication application; + + auto bloomview = BloomView::New(); + DALI_TEST_CHECK( bloomview ); + + auto accessible = Dali::Accessibility::Accessible::Get( bloomview ); + DALI_TEST_CHECK( accessible ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::ANIMATION, TEST_LOCATION ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityTextField(void) +{ + ToolkitTestApplication application; + + auto textfield = TextField::New(); + DALI_TEST_CHECK( textfield ); + + textfield.SetProperty(Actor::Property::NAME, "test" ); + DALI_TEST_EQUALS( textfield.GetProperty(Actor::Property::NAME), "test", TEST_LOCATION ); + + auto accessible = Dali::Accessibility::Accessible::Get( textfield ); + DALI_TEST_CHECK( accessible ); + + DALI_TEST_EQUALS( accessible->GetName(), "", TEST_LOCATION ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::ENTRY, TEST_LOCATION ); + auto states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::EDITABLE ] ), true, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + + textfield.SetProperty( Toolkit::TextField::Property::TEXT, "test" ); + auto text = dynamic_cast< Dali::Accessibility::Text* >( accessible ); + DALI_TEST_CHECK( text ); + DALI_TEST_EQUALS( text->GetText( 0, 10 ), "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetCaretOffset(100), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetCaretOffset(2), true, TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetCaretOffset(), 2, TEST_LOCATION ); + + auto editabletext = dynamic_cast< Dali::Accessibility::EditableText* >( accessible ); + DALI_TEST_CHECK( editabletext ); + DALI_TEST_EQUALS( editabletext->CopyText( 3, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CopyText( 1, 3 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CutText( 3, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CutText( 1, 3 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetText( 0, 1 ), "t", TEST_LOCATION ); + + auto range = text->GetSelection( 1 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityTextEditor(void) +{ + ToolkitTestApplication application; + + auto texteditor = TextEditor::New(); + DALI_TEST_CHECK( texteditor ); + + texteditor.SetProperty(Actor::Property::NAME, "test" ); + DALI_TEST_EQUALS( texteditor.GetProperty(Actor::Property::NAME), "test", TEST_LOCATION ); + + auto accessible = Dali::Accessibility::Accessible::Get( texteditor ); + DALI_TEST_CHECK( accessible ); + + DALI_TEST_EQUALS( accessible->GetName(), "", TEST_LOCATION ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::ENTRY, TEST_LOCATION ); + auto states = accessible->GetStates(); + DALI_TEST_EQUALS( static_cast< unsigned int >( states[ Accessibility::State::EDITABLE ] ), true, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + + texteditor.SetProperty( Toolkit::TextEditor::Property::TEXT, "test" ); + auto text = dynamic_cast< Dali::Accessibility::Text* >( accessible ); + DALI_TEST_CHECK( text ); + DALI_TEST_EQUALS( text->GetText( 0, 10 ), "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetCaretOffset(100), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetCaretOffset(2), true, TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetCaretOffset(), 2, TEST_LOCATION ); + + auto editabletext = dynamic_cast< Dali::Accessibility::EditableText* >( accessible ); + DALI_TEST_CHECK( editabletext ); + DALI_TEST_EQUALS( editabletext->CopyText( 3, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CopyText( 1, 3 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CutText( 3, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( editabletext->CutText( 1, 3 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetText( 0, 1 ), "t", TEST_LOCATION ); + + auto range = text->GetSelection( 1 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +int UtcDaliAccessibilityTextLabel(void) +{ + ToolkitTestApplication application; + + auto textlabel = TextLabel::New(); + DALI_TEST_CHECK( textlabel ); + + textlabel.SetProperty(Actor::Property::NAME, "test" ); + DALI_TEST_EQUALS( textlabel.GetProperty(Actor::Property::NAME), "test", TEST_LOCATION ); + + auto accessible = Dali::Accessibility::Accessible::Get( textlabel ); + DALI_TEST_CHECK( accessible ); + + DALI_TEST_EQUALS( accessible->GetName(), "test", TEST_LOCATION ); + DALI_TEST_EQUALS( accessible->GetRole(), Accessibility::Role::LABEL, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( true ); + + textlabel.SetProperty( Toolkit::TextLabel::Property::TEXT, "test" ); + auto text = dynamic_cast< Dali::Accessibility::Text* >( accessible ); + DALI_TEST_CHECK( text ); + DALI_TEST_EQUALS( text->GetText( 0, 10 ), "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetText( 0, 4 ), "test", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetCaretOffset(0), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->GetCaretOffset(), 0, TEST_LOCATION ); + + auto range = text->GetSelection( 1 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( text->SetSelection( 1, 0, 1 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( text->RemoveSelection( 1 ), false, TEST_LOCATION ); + + Dali::Accessibility::TestEnableSC( false ); + + END_TEST; +} + +#include +int UtcDaliAccessibilityNavigationViewConstructor(void) +{ + ToolkitTestApplication application; + + auto navigationview = NavigationView::New(); + DALI_TEST_CHECK( navigationview ); + + auto accessible = Dali::Accessibility::Accessible::Get( navigationview ); + DALI_TEST_CHECK( accessible ); + + DALI_TEST_EQUALS( accessible->GetRole(), Dali::Accessibility::Role::FILLER, TEST_LOCATION ); + + END_TEST; +} + +int UtcDaliAccessibilityVideoViewConstructor(void) +{ + ToolkitTestApplication application; + + auto videoview = VideoView::New(); + DALI_TEST_CHECK( videoview ); + + auto accessible = Dali::Accessibility::Accessible::Get( videoview ); + DALI_TEST_CHECK( accessible ); + + DALI_TEST_EQUALS( accessible->GetRole(), Dali::Accessibility::Role::VIDEO, TEST_LOCATION ); + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp new file mode 100644 index 0000000..7bc4fe1 --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Text.cpp @@ -0,0 +1,486 @@ +/** + * Copyright (c) 2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * + */ + +// Need to override adaptor classes for toolkit test harness, so include +// test harness headers before dali headers. +#include + +#include +#include + +#include +#include + +#include + +void utc_dali_toolkit_accessibility_text_startup(void) +{ + test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); +} + +void utc_dali_toolkit_accessibility_text_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int utcDaliAccessibilityTextEditorGetName(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + DALI_TEST_EQUALS( editor.GetProperty(Actor::Property::NAME), "", TEST_LOCATION ); + editor.SetProperty(Actor::Property::NAME, "editor"); + DALI_TEST_EQUALS( editor.GetProperty(Actor::Property::NAME), "editor", TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityTextEditorGetText(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + auto q = Dali::Accessibility::Accessible::Get( editor ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetText( 0, 0 ), "", TEST_LOCATION ); + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "exemplary_text" ); + DALI_TEST_EQUALS( x->GetText( 0, 9 ), "exemplary", TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextEditorGetCharacterCount(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + auto q = Dali::Accessibility::Accessible::Get( editor ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetCharacterCount(), 0, TEST_LOCATION ); + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "editor" ); + DALI_TEST_EQUALS( x->GetCharacterCount(), 6, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextEditorGetTextAtOffset(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + auto q = Dali::Accessibility::Accessible::Get( editor ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text editor test sentence" ); + range = x->GetTextAtOffset( 5, Dali::Accessibility::TextBoundary::CHARACTER ); + DALI_TEST_EQUALS( range.content, "e", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 5, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 6, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 3, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 28, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 36, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 4, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "text \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 6, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " editor \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 14, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 24, TEST_LOCATION ); + + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 8, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " test sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 25, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 39, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextEditorGetSetSelection(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + auto q = Dali::Accessibility::Accessible::Get( editor ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + + x->SetSelection( 0, 4, 9 ); + editor.SetProperty( Toolkit::TextEditor::Property::TEXT, "exemplary_text" ); + range = x->GetSelection( 0 ); + + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "plary", TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextEditorRemoveSelection(void) +{ + ToolkitTestApplication application; + + auto editor = Dali::Toolkit::TextEditor::New(); + auto q = Dali::Accessibility::Accessible::Get( editor ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + x->SetSelection( 0, 4, 9 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + x->RemoveSelection( 0 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextFieldGetName(void) +{ + ToolkitTestApplication application; + + auto field = Toolkit::TextField::New(); + DALI_TEST_EQUALS( field.GetProperty(Actor::Property::NAME), "", TEST_LOCATION ); + field.SetProperty(Actor::Property::NAME, "field"); + DALI_TEST_EQUALS( field.GetProperty(Actor::Property::NAME), "field", TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityTextFieldGetText(void) +{ + ToolkitTestApplication application; + + auto field = Dali::Toolkit::TextField::New(); + auto q = Dali::Accessibility::Accessible::Get( field ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetText( 0, 0 ), "", TEST_LOCATION ); + field.SetProperty( Toolkit::TextField::Property::TEXT, "exemplary_text" ); + DALI_TEST_EQUALS( x->GetText( 0, 9 ), "exemplary", TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextFieldGetCharacterCount(void) +{ + ToolkitTestApplication application; + + auto field = Dali::Toolkit::TextField::New(); + auto q = Dali::Accessibility::Accessible::Get( field ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetCharacterCount(), 0, TEST_LOCATION ); + field.SetProperty( Toolkit::TextField::Property::TEXT, "field" ); + DALI_TEST_EQUALS( x->GetCharacterCount(), 5, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextFieldGetTextAtOffset(void) +{ + ToolkitTestApplication application; + + auto field = Dali::Toolkit::TextField::New(); + auto q = Dali::Accessibility::Accessible::Get( field ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text editor test sentence" ); + range = x->GetTextAtOffset( 5, Dali::Accessibility::TextBoundary::CHARACTER ); + DALI_TEST_EQUALS( range.content, "e", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 5, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 6, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 3, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 28, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 36, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 4, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "text \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 6, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " editor \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 14, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 24, TEST_LOCATION ); + + field.SetProperty( Toolkit::TextField::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 8, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " test sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 25, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 39, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextFieldGetSetSelection(void) +{ + ToolkitTestApplication application; + + auto field = Dali::Toolkit::TextField::New(); + auto q = Dali::Accessibility::Accessible::Get( field ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + + x->SetSelection( 0, 4, 9 ); + field.SetProperty( Toolkit::TextEditor::Property::TEXT, "exemplary_text" ); + range = x->GetSelection( 0 ); + + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + DALI_TEST_EQUALS( range.content, "plary", TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextFieldRemoveSelection(void) +{ + ToolkitTestApplication application; + + auto field = Dali::Toolkit::TextField::New(); + auto q = Dali::Accessibility::Accessible::Get( field ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + x->SetSelection( 0, 4, 9 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + x->RemoveSelection( 0 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextLabelGetName(void) +{ + ToolkitTestApplication application; + + auto label = Toolkit::TextLabel::New(); + DALI_TEST_EQUALS( label.GetProperty(Actor::Property::NAME), "", TEST_LOCATION ); + label.SetProperty(Actor::Property::NAME, "label"); + DALI_TEST_EQUALS( label.GetProperty(Actor::Property::NAME), "label", TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityTextLabelGetText(void) +{ + ToolkitTestApplication application; + + auto label = Dali::Toolkit::TextLabel::New(); + auto q = Dali::Accessibility::Accessible::Get( label ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetText( 0, 0 ), "", TEST_LOCATION ); + label.SetProperty( Toolkit::TextField::Property::TEXT, "exemplary_text" ); + DALI_TEST_EQUALS( x->GetText( 0, 9 ), "exemplary", TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextLabelGetCharacterCount(void) +{ + ToolkitTestApplication application; + + auto label = Dali::Toolkit::TextLabel::New(); + auto q = Dali::Accessibility::Accessible::Get( label ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + DALI_TEST_EQUALS( x->GetCharacterCount(), 0, TEST_LOCATION ); + label.SetProperty( Toolkit::TextField::Property::TEXT, "field" ); + DALI_TEST_EQUALS( x->GetCharacterCount(), 5, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextLabelGetTextAtOffset(void) +{ + ToolkitTestApplication application; + + auto label = Dali::Toolkit::TextLabel::New(); + auto q = Dali::Accessibility::Accessible::Get( label ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text editor test sentence" ); + range = x->GetTextAtOffset( 5, Dali::Accessibility::TextBoundary::CHARACTER ); + DALI_TEST_EQUALS( range.content, "e", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 5, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 6, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 3, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 28, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 36, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 4, Dali::Accessibility::TextBoundary::WORD ); + DALI_TEST_EQUALS( range.content, "", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 0, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, "text \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 6, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " editor \n", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 14, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 24, TEST_LOCATION ); + + label.SetProperty( Toolkit::TextLabel::Property::TEXT, "text \n\n\n\n\n\n editor \n\n test sentence" ); + range = x->GetTextAtOffset( 8, Dali::Accessibility::TextBoundary::LINE ); + DALI_TEST_EQUALS( range.content, " test sentence", TEST_LOCATION ); + DALI_TEST_EQUALS( range.startOffset, 25, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 39, TEST_LOCATION ); + } + + END_TEST; +} + +int utcDaliAccessibilityTextLabelRemoveSelection( void ) +{ + ToolkitTestApplication application; + + auto label = Dali::Toolkit::TextLabel::New(); + auto q = Dali::Accessibility::Accessible::Get( label ); + auto x = dynamic_cast< Dali::Accessibility::Text* >( q ); + DALI_TEST_CHECK( x ); + if( x ) + { + auto range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + + x->SetSelection( 0, 4, 9 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 4, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 9, TEST_LOCATION ); + + x->RemoveSelection( 0 ); + range = x->GetSelection( 0 ); + DALI_TEST_EQUALS( range.startOffset, 0, TEST_LOCATION ); + DALI_TEST_EQUALS( range.endOffset, 0, TEST_LOCATION ); + } + + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Value.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Value.cpp new file mode 100644 index 0000000..af4739b --- /dev/null +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-Accessibility-Value.cpp @@ -0,0 +1,268 @@ +/** + * Copyright (c) 2017 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + * + */ + +// Need to override adaptor classes for toolkit test harness, so include +// test harness headers before dali headers. +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +using namespace Dali::Accessibility; + +void utc_dali_toolkit_accessibility_value_startup(void) +{ + test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); +} + +void utc_dali_toolkit_accessibility_value_cleanup(void) +{ + test_return_value = TET_PASS; +} + +int utcDaliAccessibilityProgressBarGetMinimum(void) +{ + ToolkitTestApplication application; + + Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New(); + auto q = Dali::Accessibility::Accessible::Get( progress_bar ); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimum(), 0.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityProgressBarGetMaximum(void) +{ + ToolkitTestApplication application; + + Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New(); + auto q = Dali::Accessibility::Accessible::Get( progress_bar ); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMaximum(), 1.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityProgressBarGetMinimumIncrement(void) +{ + ToolkitTestApplication application; + + Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New(); + auto q = Dali::Accessibility::Accessible::Get(progress_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimumIncrement(), 0.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityProgressBarGetSetCurrent(void) +{ + ToolkitTestApplication application; + + Toolkit::ProgressBar progress_bar = Toolkit::ProgressBar::New(); + auto q = Dali::Accessibility::Accessible::Get(progress_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.25, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityScrollBarGetMinimum(void) +{ + ToolkitTestApplication application; + + // Create a source actor that owns the scroll properties required by the scroll bar + Actor sourceActor = Actor::New(); + Stage::GetCurrent().Add( sourceActor ); + + // Register the scroll properties + Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition", 0.0f ); + Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin", 10.0f ); + Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax", 100.0f ); + Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize", 500.0f ); + + Toolkit::ScrollBar scroll_bar = Toolkit::ScrollBar::New(); + + scroll_bar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize); + + auto q = Dali::Accessibility::Accessible::Get(scroll_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimum(), 10.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityScrollBarGetMaximum(void) +{ + ToolkitTestApplication application; + + // Create a source actor that owns the scroll properties required by the scroll bar + Actor sourceActor = Actor::New(); + Stage::GetCurrent().Add( sourceActor ); + + // Register the scroll properties + Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition", 0.0f ); + Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin", 0.0f ); + Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax", 100.0f ); + Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize", 500.0f ); + + Toolkit::ScrollBar scroll_bar = Toolkit::ScrollBar::New(); + + scroll_bar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize); + + auto q = Dali::Accessibility::Accessible::Get(scroll_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMaximum(), 100.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityScrollBarGetMinimumIncrement(void) +{ + ToolkitTestApplication application; + + Toolkit::ScrollBar scroll_bar = Toolkit::ScrollBar::New(); + auto q = Dali::Accessibility::Accessible::Get(scroll_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimumIncrement(), 1.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilityScrollBarGetSetCurrent(void) +{ + ToolkitTestApplication application; + + // Create a source actor that owns the scroll properties required by the scroll bar + Actor sourceActor = Actor::New(); + Stage::GetCurrent().Add( sourceActor ); + + // Register the scroll properties + Property::Index propertyScrollPosition = sourceActor.RegisterProperty( "sourcePosition", 0.0f ); + Property::Index propertyMinScrollPosition = sourceActor.RegisterProperty( "sourcePositionMin", 0.0f ); + Property::Index propertyMaxScrollPosition = sourceActor.RegisterProperty( "sourcePositionMax", 100.0f ); + Property::Index propertyScrollContentSize = sourceActor.RegisterProperty( "sourceContentSize", 500.0f ); + + Toolkit::ScrollBar scroll_bar = Toolkit::ScrollBar::New(); + + scroll_bar.SetScrollPropertySource(sourceActor, propertyScrollPosition, propertyMinScrollPosition, propertyMaxScrollPosition, propertyScrollContentSize); + + //sourceActor.SetProperty(propertyScrollPosition, 20.0f); + + auto q = Dali::Accessibility::Accessible::Get(scroll_bar); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 1000.0 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 50.0 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilitySliderGetMinimum(void) +{ + ToolkitTestApplication application; + + Toolkit::Slider slider = Toolkit::Slider::New(); + auto q = Dali::Accessibility::Accessible::Get(slider); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimum(), 0.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilitySliderGetMaximum(void) +{ + ToolkitTestApplication application; + + Toolkit::Slider slider = Toolkit::Slider::New(); + auto q = Dali::Accessibility::Accessible::Get(slider); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMaximum(), 1.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilitySliderGetMinimumIncrement(void) +{ + ToolkitTestApplication application; + + Toolkit::Slider slider = Toolkit::Slider::New(); + auto q = Dali::Accessibility::Accessible::Get(slider); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetMinimumIncrement(), 0.0, TEST_LOCATION ); + + END_TEST; +} + +int utcDaliAccessibilitySliderGetSetCurrent(void) +{ + ToolkitTestApplication application; + + Toolkit::Slider slider = Toolkit::Slider::New(); + auto q = Dali::Accessibility::Accessible::Get(slider); + auto x = dynamic_cast< Dali::Accessibility::Value* >( q ); + DALI_TEST_CHECK( x ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.0, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 2.0 ), false, TEST_LOCATION ); + DALI_TEST_EQUALS( x->SetCurrent( 0.25 ), true, TEST_LOCATION ); + DALI_TEST_EQUALS( x->GetCurrent(), 0.25, TEST_LOCATION ); + + const float MIN_BOUND = 0.0f; + const float MAX_BOUND = 1.0f; + const int NUM_MARKS = 5; + Property::Array marks; + for( int i = 0; i < NUM_MARKS; ++i ) + { + marks.PushBack( MIN_BOUND + ( static_cast(i) / ( NUM_MARKS - 1) ) * ( MAX_BOUND - MIN_BOUND ) ); + } + slider.SetProperty( Toolkit::Slider::Property::MARKS, marks ); + // when current value is not a mark, set new value to the closest mark + DALI_TEST_CHECK( x->SetCurrent( 0.1f ) ); + slider.SetProperty( Toolkit::Slider::Property::SNAP_TO_MARKS, true ); + DALI_TEST_CHECK( x->SetCurrent( 0.7f ) ); + DALI_TEST_EQUALS( static_cast( x->GetCurrent() ), marks[3].Get(), TEST_LOCATION ); + // when current value is a mark at index i set new value to the mark at index i +/- 1 + // depending if the new value is greater/less than current value + DALI_TEST_CHECK( x->SetCurrent( 0.2f ) ); + DALI_TEST_EQUALS( static_cast( x->GetCurrent() ), marks[2].Get(), TEST_LOCATION ); + END_TEST; +} diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp index 14cef1c..6e41930 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-ColorConversion.cpp @@ -18,12 +18,15 @@ #include #include +#include + using namespace Dali; using namespace Dali::Toolkit; void dali_color_conversion_startup(void) { test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); } void dali_color_conversion_cleanup(void) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp index fe01738..12276e8 100755 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-DebugRendering.cpp @@ -25,6 +25,9 @@ #include #include // for setting environment variable: DALI_DEBUG_RENDERING + +#include + #include "dummy-control.h" using namespace Dali; @@ -75,6 +78,7 @@ void TestDebugVisual( Integration::Scene scene, Visual::Base& visual, Visual::T void dali_debug_rendering_startup(void) { test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); } void dali_debug_rendering_cleanup(void) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp index 58fc510..df76c38 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-PropertyHelper.cpp @@ -18,12 +18,15 @@ #include #include +#include + using namespace Dali; using namespace Dali::Toolkit; void dali_property_helper_startup(void) { test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); } void dali_property_helper_cleanup(void) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextSelectionPopup-internal.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextSelectionPopup-internal.cpp index 13c7ca8..06ce4c8 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextSelectionPopup-internal.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextSelectionPopup-internal.cpp @@ -24,12 +24,15 @@ #include #undef private +#include + using namespace Dali; using namespace Toolkit; void dali_textselectionpopupinternal_startup(void) { test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); } void dali_textselectionpopupinternal_cleanup(void) diff --git a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp index a6b7460..c1ea9ad 100644 --- a/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp +++ b/automated-tests/src/dali-toolkit-internal/utc-Dali-TextureManager.cpp @@ -27,13 +27,15 @@ #include #include -using namespace Dali::Toolkit::Internal; +#include +using namespace Dali::Toolkit::Internal; void utc_dali_toolkit_texture_manager_startup(void) { setenv( "LOG_TEXTURE_MANAGER", "3", 1 ); test_return_value = TET_UNDEF; + DBusWrapper::Install(std::unique_ptr(new TestDBusWrapper)); } void utc_dali_toolkit_texture_manager_cleanup(void) diff --git a/automated-tests/src/dali-toolkit-styling/CMakeLists.txt b/automated-tests/src/dali-toolkit-styling/CMakeLists.txt index 4148b92..bda1454 100644 --- a/automated-tests/src/dali-toolkit-styling/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-styling/CMakeLists.txt @@ -14,7 +14,6 @@ SET(TC_SOURCES LIST(APPEND TC_SOURCES ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp - ../dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp ../dali-toolkit/dali-toolkit-test-utils/toolkit-color-controller.cpp @@ -55,6 +54,7 @@ LIST(APPEND TC_SOURCES PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED dali2-core + dali2-adaptor dali2-toolkit ) diff --git a/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt b/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt index 3719b4d..e089fc6 100644 --- a/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt @@ -12,6 +12,17 @@ SET(TC_SOURCES # Append list of test harness files (Won't get parsed for test cases) LIST(APPEND TC_SOURCES + ../dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-input-method-context.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp + ../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp ../dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp ../dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index d889c6f..f21b289 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -47,7 +47,6 @@ SET(TC_SOURCES utc-Dali-Button.cpp utc-Dali-Control.cpp utc-Dali-ControlImpl.cpp - utc-Dali-AccessibilityManager.cpp utc-Dali-ItemLayout.cpp utc-Dali-ItemView.cpp utc-Dali-KeyboardFocusManager.cpp @@ -77,7 +76,6 @@ SET(TC_SOURCES # Append list of test harness files (Won't get parsed for test cases) LIST(APPEND TC_SOURCES dali-toolkit-test-utils/toolkit-adaptor.cpp - dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp dali-toolkit-test-utils/toolkit-application.cpp dali-toolkit-test-utils/toolkit-clipboard.cpp dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp deleted file mode 100644 index 72d4106..0000000 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (c) 2020 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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 -#include -#include -#include -#include -#include - -namespace Dali -{ - -namespace Internal -{ - -namespace Adaptor -{ - -/** - * Stub for the AccessibilityAdaptor - */ -class AccessibilityAdaptor : public BaseObject -{ -public: // Creation & Destruction - - static Dali::AccessibilityAdaptor Get(); - - AccessibilityAdaptor(); - ~AccessibilityAdaptor(); - -public: - - // Functions to modify mock returns: - - void MockSetReadPosition( Vector2& position ); - - void SetEnabled(bool enabled) - { - mIsEnabled = enabled; - } - - void SendPanGesture( const AccessibilityGestureEvent& panEvent ); - -public: - - bool IsEnabled() const; - void SetActionHandler(Dali::AccessibilityActionHandler& handler); - void SetGestureHandler(Dali::AccessibilityGestureHandler& handler); - - Vector2 GetReadPosition() const; - - bool HandleActionNextEvent(bool); - bool HandleActionPreviousEvent(bool); - bool HandleActionActivateEvent(); - bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain); - bool HandleActionReadNextEvent(bool); - bool HandleActionReadPreviousEvent(bool); - bool HandleActionUpEvent(); - bool HandleActionDownEvent(); - bool HandleActionClearFocusEvent(); - bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp); - bool HandleActionBackEvent(); - bool HandleActionEnableEvent(); - bool HandleActionDisableEvent(); - bool HandleActionScrollUpEvent(); - bool HandleActionScrollDownEvent(); - bool HandleActionPageLeftEvent(); - bool HandleActionPageRightEvent(); - bool HandleActionPageUpEvent(); - bool HandleActionPageDownEvent(); - bool HandleActionMoveToFirstEvent(); - bool HandleActionMoveToLastEvent(); - bool HandleActionReadFromTopEvent(); - bool HandleActionReadFromNextEvent(); - bool HandleActionZoomEvent(); - bool HandleActionReadPauseResumeEvent(); - bool HandleActionStartStopEvent(); - -private: - - bool mIsEnabled; - Dali::AccessibilityActionHandler* mActionHandler; - Dali::AccessibilityGestureHandler* mGestureHandler; - Vector2 mReadPosition; - - static Dali::AccessibilityAdaptor mToolkitAccessibilityAdaptor; -}; - -Dali::AccessibilityAdaptor AccessibilityAdaptor::mToolkitAccessibilityAdaptor; - - -Dali::AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - if( !mToolkitAccessibilityAdaptor ) - { - mToolkitAccessibilityAdaptor = Dali::AccessibilityAdaptor( new Dali::Internal::Adaptor::AccessibilityAdaptor() ); - } - return mToolkitAccessibilityAdaptor; -} - -AccessibilityAdaptor::AccessibilityAdaptor() -: mIsEnabled(false), - mActionHandler(NULL), - mGestureHandler(NULL), - mReadPosition( 0.0f, 0.0f ) -{ -} - -AccessibilityAdaptor::~AccessibilityAdaptor() -{ -} - -Vector2 AccessibilityAdaptor::GetReadPosition() const -{ - return mReadPosition; -} - -void AccessibilityAdaptor::MockSetReadPosition( Vector2& position ) -{ - mReadPosition = position; -} - -bool AccessibilityAdaptor::IsEnabled() const -{ - return mIsEnabled; -} - -void AccessibilityAdaptor::SendPanGesture( const AccessibilityGestureEvent& panEvent ) -{ - mGestureHandler->HandlePanGesture( panEvent ); -} - -void AccessibilityAdaptor::SetActionHandler(Dali::AccessibilityActionHandler& handler) -{ - mActionHandler = &handler; -} - -void AccessibilityAdaptor::SetGestureHandler(Dali::AccessibilityGestureHandler& handler) -{ - mGestureHandler = &handler; -} - -bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback) -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionNext( true ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback) -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionPrevious( true ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionActivateEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionActivate(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionRead( allowReadAgain ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback) -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionReadNext( true ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionReadPrevious( true ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionUpEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionUp(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionDownEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionDown(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionClearFocusEvent() -{ - if( mActionHandler ) - { - return mActionHandler->ClearAccessibilityFocus(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp) -{ - if( mActionHandler ) - { - Dali::TouchEvent touch = Integration::NewTouchEvent(timeStamp, point); - return mActionHandler->AccessibilityActionScroll( touch ); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionBackEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionBack(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionEnableEvent() -{ - if( mActionHandler ) - { - return mActionHandler->ChangeAccessibilityStatus(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionDisableEvent() -{ - if( mActionHandler ) - { - return mActionHandler->ChangeAccessibilityStatus(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionScrollUpEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionScrollUp(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionScrollDownEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionScrollDown(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionPageLeftEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionPageLeft(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionPageRightEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionPageRight(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionPageUpEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionPageUp(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionPageDownEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionPageDown(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionMoveToFirstEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionMoveToFirst(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionMoveToLastEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionMoveToLast(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadFromTopEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionReadFromTop(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadFromNextEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionReadFromNext(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionZoomEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionZoom(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionReadPauseResume(); - } - return false; -} - -bool AccessibilityAdaptor::HandleActionStartStopEvent() -{ - if( mActionHandler ) - { - return mActionHandler->AccessibilityActionStartStop(); - } - return false; -} - -static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor) -{ - BaseObject& handle = adaptor.GetBaseObject(); - return static_cast(handle); -} - -static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor) -{ - const BaseObject& handle = adaptor.GetBaseObject(); - return static_cast(handle); -} - - -} // namespace Adaptor -} // namespace Internal - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -AccessibilityAdaptor::AccessibilityAdaptor() -{ -} - -AccessibilityAdaptor AccessibilityAdaptor::Get() -{ - return Internal::Adaptor::AccessibilityAdaptor::Get(); -} - -AccessibilityAdaptor::~AccessibilityAdaptor() -{ -} - -// Methods: - -Vector2 AccessibilityAdaptor::GetReadPosition() const -{ - return Internal::Adaptor::GetImplementation(*this).GetReadPosition(); -} - -bool AccessibilityAdaptor::IsEnabled() const -{ - return Internal::Adaptor::GetImplementation(*this).IsEnabled(); -} - -void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler) -{ - Internal::Adaptor::GetImplementation(*this).SetActionHandler(handler); -} - -void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler) -{ - Internal::Adaptor::GetImplementation(*this).SetGestureHandler(handler); -} - -bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionNextEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionPreviousEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionActivateEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionActivateEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadEvent( x, y, allowReadAgain ); -} - -bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadNextEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadPreviousEvent(allowEndFeedback); -} - -bool AccessibilityAdaptor::HandleActionUpEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionDownEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionClearFocusEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionClearFocusEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp) -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionScrollEvent(point, timeStamp); -} - -bool AccessibilityAdaptor::HandleActionBackEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionBackEvent(); -} - -void AccessibilityAdaptor::HandleActionEnableEvent() -{ - Internal::Adaptor::GetImplementation(*this).HandleActionEnableEvent(); -} - -void AccessibilityAdaptor::HandleActionDisableEvent() -{ - Internal::Adaptor::GetImplementation(*this).HandleActionDisableEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollUpEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionScrollUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionScrollDownEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionScrollDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageLeftEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionPageLeftEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageRightEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionPageRightEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageUpEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionPageUpEvent(); -} - -bool AccessibilityAdaptor::HandleActionPageDownEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionPageDownEvent(); -} - -bool AccessibilityAdaptor::HandleActionMoveToFirstEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionMoveToFirstEvent(); -} - -bool AccessibilityAdaptor::HandleActionMoveToLastEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionMoveToLastEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadFromTopEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadFromTopEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadFromNextEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadFromNextEvent(); -} - -bool AccessibilityAdaptor::HandleActionZoomEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionZoomEvent(); -} - -bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionReadPauseResumeEvent(); -} - -bool AccessibilityAdaptor::HandleActionStartStopEvent() -{ - return Internal::Adaptor::GetImplementation(*this).HandleActionStartStopEvent(); -} - -AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* adaptor ) -: BaseHandle( adaptor ) -{ -} - -} // namespace Dali - - -namespace Test -{ -namespace AccessibilityAdaptor -{ - -// Mock setup: - -void MockSetReadPosition( Dali::AccessibilityAdaptor adaptor, Dali::Vector2& position ) -{ - Dali::Internal::Adaptor::GetImplementation(adaptor).MockSetReadPosition( position ); -} - -void SetEnabled( Dali::AccessibilityAdaptor adaptor, bool enabled ) -{ - Dali::Internal::Adaptor::GetImplementation(adaptor).SetEnabled(enabled); -} - -void SendPanGesture( Dali::AccessibilityAdaptor adaptor, const Dali::AccessibilityGestureEvent& panEvent ) -{ - Dali::Internal::Adaptor::GetImplementation(adaptor).SendPanGesture( panEvent ); -} - -} // namespace AccessibilityAdaptor -} // namespace Test diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h deleted file mode 100644 index a463baf..0000000 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H -#define DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H - -/* - * Copyright (c) 2019 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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. - * - */ - -// EXTERNAL INCLUDES -#include -#include - -namespace Test -{ -namespace AccessibilityAdaptor -{ - -void MockSetReadPosition( Dali::AccessibilityAdaptor adaptor, Dali::Vector2& position ); -void SetEnabled( Dali::AccessibilityAdaptor adaptor, bool enabled); -void SendPanGesture( Dali::AccessibilityAdaptor adaptor, const Dali::AccessibilityGestureEvent& panEvent ); - -} // namespace AccessibilityAdaptor -} // namespace Test - -#endif // DALI_TEST_TOOLKIT_ACCESSIBILITY_ADAPTOR_H diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp index 5dbbe76..1fe86c3 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-adaptor.cpp @@ -29,34 +29,11 @@ #include #include #include +#include namespace Dali { -namespace -{ - -/////////////////////////////////////////////////////////////////////////////// -// -// LogFactoryStub -// -/////////////////////////////////////////////////////////////////////////////// - -class LogFactory : public LogFactoryInterface -{ -public: - LogFactory() = default; - virtual ~LogFactory() = default; - -private: - void InstallLogFunction() const override - { - Dali::Integration::Log::InstallLogFunction( &TestApplication::LogMessage ); - } -}; -LogFactory* gLogFactory = NULL; // For some reason, destroying this when the Adaptor is destroyed causes a crash in some test cases when running all of them. -} //unnamed namespace - namespace Internal { namespace Adaptor @@ -364,6 +341,24 @@ void Adaptor::SceneCreated() { } +class LogFactory : public LogFactoryInterface +{ +public: + virtual void InstallLogFunction() const + { + Dali::Integration::Log::LogFunction logFunction(&ToolkitTestApplication::LogMessage); + Dali::Integration::Log::InstallLogFunction(logFunction); + } + + LogFactory() + { + } + virtual ~LogFactory() + { + } +}; + +LogFactory* gLogFactory = NULL; const LogFactoryInterface& Adaptor::GetLogFactory() { if( gLogFactory == NULL ) diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp index 3e3a0d2..48173fd 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.cpp @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include #include +#include #include #include #include @@ -46,6 +47,7 @@ ToolkitTestApplication::ToolkitTestApplication( size_t surfaceWidth, size_t surf // Core needs to be initialized next before we start the adaptor InitializeCore(); + Accessibility::Accessible::SetObjectRegistry(mCore->GetObjectRegistry()); // This will also emit the window created signals AdaptorImpl::GetImpl( *mAdaptor ).Start( *mMainWindow ); diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h index 66527da..49a4c6f 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h @@ -23,6 +23,13 @@ // INTERNAL INCLUDES #include +#include +#include +#include +#include +#include "test-application.h" + +//#undef assert namespace Dali { diff --git a/automated-tests/src/dali-toolkit/utc-Dali-AccessibilityManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-AccessibilityManager.cpp deleted file mode 100644 index f0dcd1f..0000000 --- a/automated-tests/src/dali-toolkit/utc-Dali-AccessibilityManager.cpp +++ /dev/null @@ -1,2333 +0,0 @@ -/* - * Copyright (c) 2020 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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 -#include - -#include -#include - -#include -#include -#include - -using namespace Dali; -using namespace Toolkit; - - -void utc_dali_toolkit_accessibility_manager_startup(void) -{ - test_return_value = TET_UNDEF; -} - -void utc_dali_toolkit_accessibility_manager_cleanup(void) -{ - test_return_value = TET_PASS; -} - - -namespace -{ - -// Functors to test whether focus changed signal is emitted when the focus is changed -class FocusChangedCallback : public Dali::ConnectionTracker -{ -public: - FocusChangedCallback(bool& signalReceived) - : mSignalVerified(signalReceived), - mOriginalFocusedActor(), - mCurrentFocusedActor() - { - } - - void Callback(Actor originalFocusedActor, Actor currentFocusedActor) - { - tet_infoline("Verifying FocusChangedCallback()"); - - if(originalFocusedActor == mCurrentFocusedActor) - { - mSignalVerified = true; - } - - mOriginalFocusedActor = originalFocusedActor; - mCurrentFocusedActor = currentFocusedActor; - } - - void Reset() - { - mSignalVerified = false; - } - - bool& mSignalVerified; - Actor mOriginalFocusedActor; - Actor mCurrentFocusedActor; -}; - -// Functors to test whether focus overshot signal is emitted when there is no way to move focus further. -class FocusOvershotCallback : public Dali::ConnectionTracker -{ -public: - FocusOvershotCallback(bool& signalReceived) - : mSignalVerified(signalReceived), - mCurrentFocusedActor(), - mFocusOvershotDirection(Toolkit::AccessibilityManager::OVERSHOT_NEXT) - { - } - - void Callback(Actor currentFocusedActor, Toolkit::AccessibilityManager::FocusOvershotDirection direction) - { - tet_infoline("Verifying FocusOvershotCallback()"); - - if(currentFocusedActor == mCurrentFocusedActor && direction == mFocusOvershotDirection) - { - mSignalVerified = true; - } - } - - void Reset() - { - mSignalVerified = false; - } - - bool& mSignalVerified; - Actor mCurrentFocusedActor; - Toolkit::AccessibilityManager::FocusOvershotDirection mFocusOvershotDirection; -}; - -// Functor to test whether focused actor activated signal is emitted. -class FocusedActorActivatedCallback : public Dali::ConnectionTracker -{ -public: - FocusedActorActivatedCallback() - { - } - - void Callback(Actor activatedActor) - { - tet_infoline("Verifying FocusedActorActivatedCallback()"); - } -}; - -} // namespace - - -int UtcDaliAccessibilityManagerGet(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerGet"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - AccessibilityManager newManager = AccessibilityManager::Get(); - DALI_TEST_CHECK(newManager); - - // Check that accessibility manager is a singleton - DALI_TEST_CHECK(manager == newManager); - END_TEST; -} - -int UtcDaliAccessibilityManagerSetAndGetAccessibilityAttribute(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSetAndGetAccessibilityAttribute"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Actor actor = Actor::New(); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == ""); - - manager.SetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL, "Description"); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == "Description"); - - manager.SetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL, "New description"); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(actor, AccessibilityManager::ACCESSIBILITY_LABEL) == "New description"); - END_TEST; -} - -int UtcDaliAccessibilityManagerSetAndGetFocusOrder(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusOrder"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Actor first = Actor::New(); - Actor second = Actor::New(); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 0); - - // Set the focus order and description for the first actor - manager.SetFocusOrder(first, 1); - manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(second, 2); - manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second"); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // check that the focus order of the first actor is changed - manager.SetFocusOrder(first, 2); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 2); - // make sure the change of focus order doesn't affect the actor's description - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // check that the focus order of the second actor is increased to 3 - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 3); - // make sure the change of focus order doesn't affect the actor's description - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // check that the focus order of the second actor is changed to 1 - manager.SetFocusOrder(second, 1); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 1); - // make sure the change of focus order doesn't affect the actor's description - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Set the focus order and description for the third actor - Actor third = Actor::New(); - manager.SetFocusOrder(third, 1); - manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third"); - DALI_TEST_CHECK(manager.GetFocusOrder(third) == 1); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // check that the focus order of the second actor is increased to 2. - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - // make sure the change of focus order doesn't affect the actor's description - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // check that the focus order of the first actor is increased to 3. - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 3); - // make sure the change of focus order doesn't affect the actor's description - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - END_TEST; -} - -int UtcDaliAccessibilityManagerGenerateNewFocusOrder(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerGenerateNewFocusOrder"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - DALI_TEST_CHECK(1 == manager.GenerateNewFocusOrder()); - DALI_TEST_CHECK(1 == manager.GenerateNewFocusOrder()); - - Actor first = Actor::New(); - Actor second = Actor::New(); - - // Set the focus order for the first actor - manager.SetFocusOrder(first, 1); - manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1); - - //Test for new focus order - DALI_TEST_CHECK(2 == manager.GenerateNewFocusOrder()); - - // Set the focus order for the first actor - manager.SetFocusOrder(second, 2); - manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - END_TEST; -} - -int UtcDaliAccessibilityManagerGetActorByFocusOrder(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerGetActorByFocusOrder"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - // Create the actors and set their focus orders - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - - Actor third = Actor::New(); - manager.SetFocusOrder(third, 3); - - // Check that we get an empty handle as no actor is added to the stage yet. - DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == Actor()); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == Actor()); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == Actor()); - - // Add the actors to the stage - application.GetScene().Add(first); - application.GetScene().Add(second); - application.GetScene().Add(third); - - // Check that we get an empty handle because focus order 0 means undefined. - DALI_TEST_CHECK(manager.GetActorByFocusOrder(0) == Actor()); - - // Check that we get correct actors for the specified focus orders - DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == first); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == second); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == third); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Change the focus order of the third actor to 1 - manager.SetFocusOrder(third, 1); - - // Check that we still get correct actors after changing their focus orders - DALI_TEST_CHECK(manager.GetActorByFocusOrder(1) == third); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(2) == first); - DALI_TEST_CHECK(manager.GetActorByFocusOrder(3) == second); - - // Check that we get an empty handle because no actor has a focus order of 4 - DALI_TEST_CHECK(manager.GetActorByFocusOrder(4) == Actor()); - END_TEST; -} - -int UtcDaliAccessibilityManagerSetAndGetCurrentFocusActor(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSetAndGetCurrentFocusActor"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Create the first actor and add it to the stage - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - application.GetScene().Add(first); - - // Create the second actor and add it to the stage - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - application.GetScene().Add(second); - - // Create the third actor but don't add it to the stage - Actor third = Actor::New(); - manager.SetFocusOrder(third, 3); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Check that it will fail to set focus on an invalid actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(Actor()) == false); - - // Check that the focus is set on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - - // Check that the focus is set on the second actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - - // Check that it will fail to set focus on the third actor as it's not in the stage - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false); - - // Add the third actor to the stage - application.GetScene().Add(third); - - // make the third actor invisible - third.SetProperty( Actor::Property::VISIBLE,false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Check that it will fail to set focus on the third actor as it's invisible - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false); - - // Make the third actor visible - third.SetProperty( Actor::Property::VISIBLE,true); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Make the third actor not focusable - Property::Index propertyActorFocusable = third.GetPropertyIndex("focusable"); - third.SetProperty(propertyActorFocusable, false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Check that it will fail to set focus on the third actor as it's not focusable - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == false); - - // Make the third actor focusable - third.SetProperty(propertyActorFocusable, true); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Check that the focus is successfully moved to the third actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true); - - // Make the current focused actor to be not focusable by setting its focus order to be 0 - manager.SetFocusOrder(third, 0); - - // Check that the focus is automatically cleared - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Set the focus order of the third actor again - manager.SetFocusOrder(third, 3); - - // Check that the third actor can be focused successfully now - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true); - END_TEST; -} - -int UtcDaliAccessibilityManagerGetCurrentFocusGroup(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerGetCurrentFocusGroup"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Create an actor with two child actors and add it to the stage - Actor parent = Actor::New(); - Actor firstChild = Actor::New(); - Actor secondChild = Actor::New(); - parent.Add(firstChild); - parent.Add(secondChild); - application.GetScene().Add(parent); - - // Create three actors and add them as the children of the first child actor - Actor firstGrandChild = Actor::New(); - Actor secondGrandChild = Actor::New(); - Actor thirdGrandChild = Actor::New(); - firstChild.Add(firstGrandChild); - firstChild.Add(secondGrandChild); - firstChild.Add(thirdGrandChild); - - // Set focus order to the actors - manager.SetFocusOrder(parent, 1); - manager.SetFocusOrder(firstChild, 2); - manager.SetFocusOrder(firstGrandChild, 3); - manager.SetFocusOrder(secondGrandChild, 4); - manager.SetFocusOrder(thirdGrandChild, 5); - manager.SetFocusOrder(secondChild, 6); - - // Set the parent and the first child actor as focus groups - manager.SetFocusGroup(parent, true); - DALI_TEST_CHECK(manager.IsFocusGroup(parent) == true); - - // Set focus to the first grand child actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(firstGrandChild) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild); - - // The current focus group should be the parent, As it is the immediate parent which is also a focus group. - DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == parent); - - manager.SetFocusGroup(firstChild, true); - DALI_TEST_CHECK(manager.IsFocusGroup(firstChild) == true); - - // The current focus group should be the firstChild, As it is the immediate parent which is also a focus group. - DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstChild); - - manager.SetFocusGroup(firstGrandChild, true); - DALI_TEST_CHECK(manager.IsFocusGroup(firstGrandChild) == true); - - // The current focus group should be itself, As it is also a focus group. - DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstGrandChild); - - // Set focus to the second grand child actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(secondGrandChild) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild); - - // The current focus group should be the firstChild, As it is the immediate parent which is also a - // focus group for the current focus actor. - DALI_TEST_CHECK(manager.GetCurrentFocusGroup() == firstChild); - - END_TEST; -} - -int UtcDaliAccessibilityManagerGetCurrentFocusOrder(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerGetCurrentFocusOrder"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - Actor first = Actor::New(); - application.GetScene().Add(first); - - Actor second = Actor::New(); - application.GetScene().Add(second); - - Actor third = Actor::New(); - application.GetScene().Add(third); - - // Set the focus order and description for the first actor - manager.SetFocusOrder(first, 1); - manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(second, 2); - manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second"); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(third, 3); - manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third"); - DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 0); - - // Set the focus on the first actor and test - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 1); - - // Move the focus forward to the second actor and test - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 2); - - // Move the focus forward to the third actor and test - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 3); - - // Clear focus and test - manager.ClearFocus(); - DALI_TEST_CHECK(manager.GetCurrentFocusOrder() == 0); - END_TEST; -} - -int UtcDaliAccessibilityManagerMoveFocusForward(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerMoveFocusForward"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - accAdaptor.HandleActionNextEvent(true); - - Actor first = Actor::New(); - application.GetScene().Add(first); - - Actor second = Actor::New(); - application.GetScene().Add(second); - - Actor third = Actor::New(); - application.GetScene().Add(third); - - // Set the focus order and description for the first actor - manager.SetFocusOrder(first, 1); - manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(second, 2); - manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second"); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(third, 3); - manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third"); - DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Set the focus on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Test the non-wrapped move first - manager.SetWrapMode(false); - DALI_TEST_CHECK(manager.GetWrapMode() == false); - - // Move the focus forward to the second actor - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // Move the focus forward to the third actor - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Check that it will fail to move the focus forward again as the third actor is the last - // focusable actor in the focus chain - manager.MoveFocusForward(); - // The focus should still be set on the third actor - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Now test the wrapped move - manager.SetWrapMode(true); - DALI_TEST_CHECK(manager.GetWrapMode() == true); - - // Move the focus forward recursively and this time the first actor should be focused - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Make the second actor not focusable - Property::Index propertyActorFocusable = second.GetPropertyIndex("focusable"); - second.SetProperty(propertyActorFocusable, false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Move the focus forward and check that the second actor should be skipped and - // the third actor should be focused now. - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Make the first actor invisible - first.SetProperty( Actor::Property::VISIBLE,false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Move the focus forward and check that the first actor should be skipped as it's - // invisible and the second actor should also be skipped as it's not focusable, - // so the focus will still be on the third actor - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Make the third actor invisible so that no actor can be focused. - third.SetProperty( Actor::Property::VISIBLE,false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Check that the focus move is failed as all the three actors can not be focused - manager.MoveFocusForward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - END_TEST; -} - -int UtcDaliAccessibilityManagerMoveFocusBackward(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerMoveFocusBackward"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - Actor first = Actor::New(); - application.GetScene().Add(first); - - Actor second = Actor::New(); - application.GetScene().Add(second); - - Actor third = Actor::New(); - application.GetScene().Add(third); - - // Set the focus order and description for the first actor - manager.SetFocusOrder(first, 1); - manager.SetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL, "first"); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 1); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(first, AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(second, 2); - manager.SetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL, "second"); - DALI_TEST_CHECK(manager.GetFocusOrder(second) == 2); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(second, AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // Set the focus order and description for the second actor - manager.SetFocusOrder(third, 3); - manager.SetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL, "third"); - DALI_TEST_CHECK(manager.GetFocusOrder(third) == 3); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(third, AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Set the focus on the third actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(third) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Test the non-wrapped move first - manager.SetWrapMode(false); - DALI_TEST_CHECK(manager.GetWrapMode() == false); - - // Move the focus backward to the second actor - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "second"); - - // Move the focus backward to the first actor - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Check that it will fail to move the focus backward again as the first actor is the first - // focusable actor in the focus chain - manager.MoveFocusBackward(); - // The focus should still be set on the first actor - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Now test the wrapped move - manager.SetWrapMode(true); - DALI_TEST_CHECK(manager.GetWrapMode() == true); - - // Move the focus backward recursively and this time the third actor should be focused - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == third); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "third"); - - // Make the second actor not focusable - Property::Index propertyActorFocusable = second.GetPropertyIndex("focusable"); - second.SetProperty(propertyActorFocusable, false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Move the focus backward and check that the second actor should be skipped and - // the first actor should be focused now. - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Make the third actor invisible - third.SetProperty( Actor::Property::VISIBLE,false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Move the focus backward and check that the third actor should be skipped as it's - // invisible and the second actor should also be skipped as it's not focusable, - // so the focus will still be on the first actor - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - - // Make the first actor invisible so that no actor can be focused. - first.SetProperty( Actor::Property::VISIBLE,false); - // flush the queue and render once - application.SendNotification(); - application.Render(); - - // Check that the focus move is failed as all the three actors can not be focused - manager.MoveFocusBackward(); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(manager.GetAccessibilityAttribute(manager.GetCurrentFocusActor(), AccessibilityManager::ACCESSIBILITY_LABEL) == "first"); - END_TEST; -} - -int UtcDaliAccessibilityManagerClearFocus(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerClearFocus"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Create the first actor and add it to the stage - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - application.GetScene().Add(first); - - // Create the second actor and add it to the stage - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - application.GetScene().Add(second); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Check that the focus is set on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - - // Check that the focus is set on the second actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - - // Clear the focus - manager.ClearFocus(); - - // Check that no actor is being focused now. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - END_TEST; -} - -int UtcDaliAccessibilityManagerReset(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerReset"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - // Create the first actor and add it to the stage - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - application.GetScene().Add(first); - - // Create the second actor and add it to the stage - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - application.GetScene().Add(second); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Check that the focus is set on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - - // Check that the focus is set on the second actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - - // Clear the focus - manager.Reset(); - - // Check that no actor is being focused now and the focus order of actors have been cleared - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0); - DALI_TEST_CHECK(manager.GetFocusOrder(first) == 0); - END_TEST; -} - -int UtcDaliAccessibilityManagerFocusGroup(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerFocusGroup"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - // Create an actor with two child actors and add it to the stage - Actor parent = Actor::New(); - Actor firstChild = Actor::New(); - Actor secondChild = Actor::New(); - parent.Add(firstChild); - parent.Add(secondChild); - application.GetScene().Add(parent); - - // Create three actors and add them as the children of the first child actor - Actor firstGrandChild = Actor::New(); - Actor secondGrandChild = Actor::New(); - Actor thirdGrandChild = Actor::New(); - firstChild.Add(firstGrandChild); - firstChild.Add(secondGrandChild); - firstChild.Add(thirdGrandChild); - - // Set focus order to the actors - manager.SetFocusOrder(parent, 1); - manager.SetFocusOrder(firstChild, 2); - manager.SetFocusOrder(firstGrandChild, 3); - manager.SetFocusOrder(secondGrandChild, 4); - manager.SetFocusOrder(thirdGrandChild, 5); - manager.SetFocusOrder(secondChild, 6); - - // Set the parent and the first child actor as focus groups - manager.SetFocusGroup(parent, true); - DALI_TEST_CHECK(manager.IsFocusGroup(parent) == true); - - // The focus group of the parent should be itself, as it is set to be a focus group. - DALI_TEST_CHECK(manager.GetFocusGroup(parent) == parent); - - // The focus group of the firstChild should be its parent, as it is the immediate parent which is also a group. - DALI_TEST_CHECK(manager.GetFocusGroup(firstChild) == parent); - - manager.SetFocusGroup(firstChild, true); - DALI_TEST_CHECK(manager.IsFocusGroup(firstChild) == true); - - // The focus group of the firstChild should be itself, as it is set to be a focus group now. - DALI_TEST_CHECK(manager.GetFocusGroup(firstChild) == firstChild); - - // Enable wrap mode for focus movement. - manager.SetWrapMode(true); - DALI_TEST_CHECK(manager.GetWrapMode() == true); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Check that the focus is set on the parent actor. - DALI_TEST_CHECK(manager.SetCurrentFocusActor(parent) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == parent); - - // Check that group mode is disabled. - DALI_TEST_CHECK(manager.GetGroupMode() == false); - - // Check that the focus movement is wrapped as normal. - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == thirdGrandChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == parent); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild); - - // Enable the group mode. - manager.SetGroupMode(true); - DALI_TEST_CHECK(manager.GetGroupMode() == true); - - // Check that the focus movement is now limited to the current focus group. - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == secondGrandChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == thirdGrandChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstChild); - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == firstGrandChild); - END_TEST; -} - -int UtcDaliAccessibilityManagerSetAndGetFocusIndicator(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusIndicator"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Actor defaultFocusIndicatorActor = manager.GetFocusIndicatorActor(); - DALI_TEST_CHECK(defaultFocusIndicatorActor); - - Actor newFocusIndicatorActor = Actor::New(); - manager.SetFocusIndicatorActor(newFocusIndicatorActor); - DALI_TEST_CHECK(manager.GetFocusIndicatorActor() == newFocusIndicatorActor); - END_TEST; -} - -int UtcDaliAccessibilityManagerSetAndGetFocusIndicatorWithFocusedActor(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSetAndGetFocusIndicatorWithFocusedActor"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - Actor defaultFocusIndicatorActor = manager.GetFocusIndicatorActor(); - DALI_TEST_CHECK(defaultFocusIndicatorActor); - - Actor focusedActor = Actor::New(); - application.GetScene().Add( focusedActor ); - - application.SendNotification(); - application.Render(); - - DALI_TEST_EQUALS( focusedActor.GetChildCount(), 0u, TEST_LOCATION ); - - manager.SetFocusOrder( focusedActor, 1 ); - manager.SetCurrentFocusActor( focusedActor ); - - DALI_TEST_EQUALS( focusedActor.GetChildCount(), 1u, TEST_LOCATION ); - DALI_TEST_CHECK( focusedActor.GetChildAt(0) == defaultFocusIndicatorActor ); - - Actor newFocusIndicatorActor = Actor::New(); - manager.SetFocusIndicatorActor( newFocusIndicatorActor ); - DALI_TEST_CHECK(manager.GetFocusIndicatorActor() == newFocusIndicatorActor); - DALI_TEST_EQUALS( focusedActor.GetChildCount(), 1u, TEST_LOCATION ); - DALI_TEST_CHECK( focusedActor.GetChildAt(0) == newFocusIndicatorActor ); - - // Disable Accessibility - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, false ); - accAdaptor.HandleActionEnableEvent(); - - DALI_TEST_EQUALS( focusedActor.GetChildCount(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerSignalFocusChanged(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSignalFocusChanged"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - bool signalVerified = false; - FocusChangedCallback callback(signalVerified); - manager.FocusChangedSignal().Connect( &callback, &FocusChangedCallback::Callback ); - - // Create the first actor and add it to the stage - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - application.GetScene().Add(first); - - // Create the second actor and add it to the stage - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - application.GetScene().Add(second); - - // Check that no actor is being focused yet. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - - // Check that the focus is set on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(callback.mSignalVerified); - callback.Reset(); - - // Check that the focus is set on the second actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(second) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - DALI_TEST_CHECK(callback.mSignalVerified); - callback.Reset(); - - // Clear the focus - manager.ClearFocus(); - - // Check that no actor is being focused now. - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == Actor()); - DALI_TEST_CHECK(callback.mSignalVerified); - END_TEST; -} - -int UtcDaliAccessibilityManagerSignalFocusOvershot(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSignalFocusOvershot"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - bool signalVerified = false; - FocusOvershotCallback callback(signalVerified); - manager.FocusOvershotSignal().Connect(&callback, &FocusOvershotCallback::Callback); - - // Create the first actor and add it to the stage - Actor first = Actor::New(); - manager.SetFocusOrder(first, 1); - application.GetScene().Add(first); - - // Create the second actor and add it to the stage - Actor second = Actor::New(); - manager.SetFocusOrder(second, 2); - application.GetScene().Add(second); - - // Check that the wrap mode is disabled - DALI_TEST_CHECK(manager.GetWrapMode() == false); - - // Check that the focus is set on the first actor - DALI_TEST_CHECK(manager.SetCurrentFocusActor(first) == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - - // Check that the focus is moved to the second actor successfully. - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - - // Check that the forward focus movement is overshot. - callback.mCurrentFocusedActor = second; - callback.mFocusOvershotDirection = Toolkit::AccessibilityManager::OVERSHOT_NEXT; - DALI_TEST_CHECK(manager.MoveFocusForward() == false); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == second); - DALI_TEST_CHECK(signalVerified); - callback.Reset(); - - // Enable the wrap mode - manager.SetWrapMode(true); - DALI_TEST_CHECK(manager.GetWrapMode() == true); - - // Check that the forward focus movement is wrapped and no overshot happens. - DALI_TEST_CHECK(manager.MoveFocusForward() == true); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(signalVerified == false); - - // Disable the wrap mode - manager.SetWrapMode(false); - DALI_TEST_CHECK(manager.GetWrapMode() == false); - - // Check that the backward focus movement is overshot. - callback.mCurrentFocusedActor = first; - callback.mFocusOvershotDirection = Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS; - DALI_TEST_CHECK(manager.MoveFocusBackward() == false); - DALI_TEST_CHECK(manager.GetCurrentFocusActor() == first); - DALI_TEST_CHECK(signalVerified); - END_TEST; -} - -int UtcDaliAccessibilityManagerSignalFocusedActorActivated(void) -{ - ToolkitTestApplication application; - - tet_infoline(" UtcDaliAccessibilityManagerSignalFocusedActorActivated"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK(manager); - - FocusedActorActivatedCallback callback; - manager.FocusedActorActivatedSignal().Connect(&callback, &FocusedActorActivatedCallback::Callback); - DALI_TEST_CHECK(true); - - END_TEST; -} - -// Note: No negative test for GetReadPosition as it will always return something. -int UtcDaliAccessibilityManagerGetReadPositionP(void) -{ - ToolkitTestApplication application; - tet_infoline(" UtcDaliAccessibilityManagerGetReadPositionP"); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - Vector2 readPosition( manager.GetReadPosition() ); - DALI_TEST_EQUALS( readPosition.x, 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION ); - DALI_TEST_EQUALS( readPosition.y, 0.0f, Math::MACHINE_EPSILON_0, TEST_LOCATION ); - - END_TEST; -} - -// Functor to test if an accessibility signal has been called. -class AccessibilityManagerSignalHandler : public Dali::ConnectionTracker -{ -public: - AccessibilityManagerSignalHandler() : - mCalls( 0 ) - { - } - - bool Callback( AccessibilityManager& accessibilityManager ) - { - mCalls++; - tet_infoline( "Signal called" ); - return true; - } - - unsigned int GetCalls() const - { - return mCalls; - } - -private: - unsigned int mCalls; ///< Keeps track of how many times the signal has been called. -}; - -int UtcDaliAccessibilityManagerStatusChangedSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerStatusChangedSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.StatusChangedSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - // Cause a state change. - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionEnableEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerStatusChangedSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerStatusChangedSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.StatusChangedSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionNextSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionNextSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionNextEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionNextSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionNextSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPreviousSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPreviousSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionPreviousEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPreviousSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPreviousSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionActivateSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionActivateSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New(); - button.SetProperty( Actor::Property::SIZE, Vector2(480, 800) ); - application.GetScene().Add(button); - manager.SetFocusOrder( button, 1 ); - manager.SetCurrentFocusActor( button ); - - manager.ActionActivateSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionActivateEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionActivateSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionActivateSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionActivateSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadEvent( 100.0f, 200.0f, true ); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadSignalN" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionOverSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionOverSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionOverSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - // Note that the ActionOverSignal is provoked by a read even when "allow read again" is set to false. - accessibilityAdaptor.HandleActionReadEvent( 100.0f, 200.0f, false ); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionOverSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionOverSignalN" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionOverSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadNextSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadNextSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadNextEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadNextSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadNextSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadPreviousSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadPreviousSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadPreviousEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadPreviousSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadPreviousSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadPreviousSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionUpSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionUpSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accessibilityAdaptor, true ); - accessibilityAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - DummyControl dummyControl = DummyControl::New(true); - dummyControl.SetProperty( Actor::Property::SIZE, Vector2(480, 800) ); - manager.SetFocusOrder( dummyControl, 1 ); - application.GetScene().Add( dummyControl ); - manager.SetCurrentFocusActor( dummyControl ); - - accessibilityAdaptor.HandleActionUpEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionUpSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionUpSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionDownSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionDownSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accessibilityAdaptor, true ); - accessibilityAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New(); - button.SetProperty( Actor::Property::SIZE, Vector2(480, 800) ); - application.GetScene().Add(button); - manager.SetFocusOrder( button, 1 ); - manager.SetCurrentFocusActor( button ); - - accessibilityAdaptor.HandleActionDownEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionDownSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionDownSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionClearFocusSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionClearFocusSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionClearFocusSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionClearFocusEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionClearFocusSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionClearFocusSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionClearFocusSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionBackSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionBackSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionBackSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionBackEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionBackSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionBackSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionBackSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionScrollUpSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollUpSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionScrollUpEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionScrollUpSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollUpSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionScrollDownSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollDownSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionScrollDownEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionScrollDownSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollDownSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageLeftSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageLeftSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageLeftSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionPageLeftEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageLeftSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageLeftSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageLeftSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageRightSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageRightSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageRightSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionPageRightEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageRightSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageRightSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageRightSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageUpSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageUpSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionPageUpEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageUpSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageUpSignalN" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageUpSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageDownSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageDownSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionPageDownEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionPageDownSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionPageDownSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionPageDownSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionMoveToFirstSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionMoveToFirstSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionMoveToFirstSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionMoveToFirstEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - - -int UtcDaliAccessibilityManagerActionMoveToFirstSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionMoveToFirstSignalN" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionMoveToFirstSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionMoveToLastSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionMoveToLastSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionMoveToLastSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionMoveToLastEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionMoveToLastSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionMoveToLastSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionMoveToLastSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadFromTopSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadFromTopSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadFromTopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadFromTopEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadFromTopSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadFromTopSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadFromTopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadFromNextSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadFromNextSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadFromNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadFromNextEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadFromNextSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadFromNextSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadFromNextSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionZoomSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionZoomSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - Dali::Toolkit::PushButton button = Dali::Toolkit::PushButton::New(); - button.SetProperty( Actor::Property::SIZE, Vector2(480, 800) ); - application.GetScene().Add(button); - manager.SetFocusOrder( button, 1 ); - manager.SetCurrentFocusActor( button ); - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - manager.ActionZoomSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionZoomEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionZoomSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionZoomSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionZoomSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadPauseResumeSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadPauseResumeSignalP" ); - - AccessibilityManagerSignalHandler callback; - - Dali::AccessibilityAdaptor accAdaptor = Dali::AccessibilityAdaptor::Get(); - Test::AccessibilityAdaptor::SetEnabled( accAdaptor, true ); - accAdaptor.HandleActionEnableEvent(); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadPauseResumeSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionReadPauseResumeEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionReadPauseResumeSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionReadPauseResumeSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionReadPauseResumeSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionStartStopSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionStartStopSignalP" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionStartStopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - accessibilityAdaptor.HandleActionStartStopEvent(); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionStartStopSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionStartStopSignalN" ); - - AccessibilityManagerSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionStartStopSignal().Connect( &callback, &AccessibilityManagerSignalHandler::Callback ); - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -// Functor to test if a accessibility scroll signal has been called. -class AccessibilityManagerScrollSignalHandler : public Dali::ConnectionTracker -{ -public: - AccessibilityManagerScrollSignalHandler() : - mCalls( 0 ) - { - } - - bool Callback( AccessibilityManager& accessibilityManager, const Dali::TouchEvent& touchEvent ) - { - mCalls++; - Dali::TouchEvent handle(touchEvent); // Ensure it's ref-counted - mTouchEvent = handle; - tet_infoline( "Signal called" ); - return true; - } - - unsigned int GetCalls() const - { - return mCalls; - } - - const Dali::TouchEvent& GetTouchEvent() const - { - return mTouchEvent; - } - -private: - unsigned int mCalls; ///< Keeps track of how many times the signal has been called. - Dali::TouchEvent mTouchEvent ; ///< Stores the last touch event received. -}; - -int UtcDaliAccessibilityManagerActionScrollSignalP(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollSignalP" ); - - AccessibilityManagerScrollSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollSignal().Connect( &callback, &AccessibilityManagerScrollSignalHandler::Callback ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - - TouchPoint point( 0, PointState::STARTED, 100.0f, 200.0f ); - accessibilityAdaptor.HandleActionScrollEvent( point, 0u ); - - DALI_TEST_EQUALS( callback.GetCalls(), 1u, TEST_LOCATION ); - - const TouchEvent& signalTouchEvent = callback.GetTouchEvent(); - DALI_TEST_EQUALS( signalTouchEvent.GetPointCount(), 1u, TEST_LOCATION ); - - - DALI_TEST_EQUALS( signalTouchEvent.GetState(0), PointState::STARTED, TEST_LOCATION ); - DALI_TEST_EQUALS( signalTouchEvent.GetScreenPosition(0).x, 100.0f, TEST_LOCATION ); - DALI_TEST_EQUALS( signalTouchEvent.GetScreenPosition(0).y, 200.0f, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerActionScrollSignalN(void) -{ - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerActionScrollSignalN" ); - - AccessibilityManagerScrollSignalHandler callback; - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - manager.ActionScrollSignal().Connect( &callback, &AccessibilityManagerScrollSignalHandler::Callback ); - - DALI_TEST_EQUALS( callback.GetCalls(), 0u, TEST_LOCATION ); - - END_TEST; -} - -int UtcDaliAccessibilityManagerHandlePanGesture(void) -{ - // Pan gesture sent from adaptor to manager via AccessibilityGestureHandler - // Adaptor.SetGestureHandler is called in Initialize (check it's the toolkit version) - ToolkitTestApplication application; - tet_infoline( " UtcDaliAccessibilityManagerHandlePanGesture" ); - - AccessibilityManager manager = AccessibilityManager::Get(); - DALI_TEST_CHECK( manager ); - - Dali::AccessibilityAdaptor accessibilityAdaptor = Dali::AccessibilityAdaptor::Get(); - DummyControl dummyControl = DummyControl::New(true); - dummyControl.SetProperty( Actor::Property::SIZE, Vector2(480, 800) ); - application.GetScene().Add( dummyControl ); - - AccessibilityGestureEvent panGestureEvent(AccessibilityGestureEvent::STARTED); - panGestureEvent.previousPosition = Vector2(0.f, 0.f); - panGestureEvent.currentPosition = Vector2(100.f, 0.f); - panGestureEvent.timeDelta = 16; - panGestureEvent.numberOfTouches = 1; - - Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent ); - - panGestureEvent.state = AccessibilityGestureEvent::CONTINUING; - panGestureEvent.previousPosition = Vector2(100.f, 0.f); - panGestureEvent.currentPosition = Vector2(200.f, 0.f); - Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent ); - - panGestureEvent.state = AccessibilityGestureEvent::FINISHED; - panGestureEvent.previousPosition = Vector2(200.f, 0.f); - panGestureEvent.currentPosition = Vector2(300.f, 0.f); - Test::AccessibilityAdaptor::SendPanGesture( accessibilityAdaptor, panGestureEvent ); - - - END_TEST; -} - -// Methods missing coverage: -// IsActorFocusableFunction -// DoActivate -// SetFocusable -// TtsStateChanged diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp index e99c8f7..83ebfb6 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Button.cpp @@ -143,7 +143,7 @@ Dali::Integration::Point GetPointUpOutside() int UtcDaliButtonConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; Button button; @@ -153,7 +153,7 @@ int UtcDaliButtonConstructorP(void) int UtcDaliButtonCopyConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; // Initialize an object, ref count == 1 Button button = PushButton::New(); @@ -184,7 +184,7 @@ int UtcDaliButtonMoveConstructor(void) int UtcDaliButtonAssignmentOperatorP(void) { - TestApplication application; + ToolkitTestApplication application; Button button = PushButton::New(); @@ -217,7 +217,7 @@ int UtcDaliButtonMoveAssignment(void) int UtcDaliButtonDownCastP(void) { - TestApplication application; + ToolkitTestApplication application; Button button = PushButton::New(); @@ -233,7 +233,7 @@ int UtcDaliButtonDownCastP(void) int UtcDaliButtonDownCastN(void) { - TestApplication application; + ToolkitTestApplication application; BaseHandle unInitializedObject; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp index e60505d..f1b934b 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ControlWrapper.cpp @@ -289,7 +289,7 @@ int UtcDaliControlWrapperConstructor(void) int UtcDaliControlWrapperDestructor(void) { - TestApplication application; + ToolkitTestApplication application; ControlWrapper control = ControlWrapper::New( customControlTypeName, *( new Toolkit::Internal::ControlWrapper( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ) ) ); @@ -308,7 +308,7 @@ int UtcDaliControlWrapperDestructor(void) int UtcDaliControlWrapperRelayoutRequest(void) { - TestApplication application; + ToolkitTestApplication application; DALI_TEST_EQUALS( gOnRelayout, false, TEST_LOCATION ); @@ -334,7 +334,7 @@ int UtcDaliControlWrapperRelayoutRequest(void) int UtcDaliControlWrapperImplGetHeightForWidthBase(void) { - TestApplication application; + ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); @@ -354,7 +354,7 @@ int UtcDaliControlWrapperImplGetHeightForWidthBase(void) int UtcDaliControlWrapperGetWidthForHeightBase(void) { - TestApplication application; + ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); @@ -374,7 +374,7 @@ int UtcDaliControlWrapperGetWidthForHeightBase(void) int UtcDaliControlWrapperCalculateChildSizeBase(void) { - TestApplication application; + ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); @@ -395,7 +395,7 @@ int UtcDaliControlWrapperCalculateChildSizeBase(void) int UtcDaliControlWrapperRelayoutDependentOnChildrenBase(void) { - TestApplication application; + ToolkitTestApplication application; Impl::TestCustomControl* controlWrapperImpl = new ::Impl::TestCustomControl( Toolkit::Internal::ControlWrapper::CONTROL_BEHAVIOUR_DEFAULT ); ControlWrapper controlWrapper = ControlWrapper::New( customControlTypeName, *controlWrapperImpl ); @@ -609,7 +609,7 @@ int UtcDaliControlWrapperRegisterUnregisterVisual(void) int UtcDaliControlWrapperTransitionDataMap1N(void) { - TestApplication application; + ToolkitTestApplication application; Property::Map map; map["target"] = "Actor1"; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp index 044018b..5913861 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-PushButton.cpp @@ -167,7 +167,7 @@ static std::string GetButtonText( Button button ) int UtcDaliPushButtonConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; PushButton button; @@ -177,7 +177,7 @@ int UtcDaliPushButtonConstructorP(void) int UtcDaliPushButtonCopyConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; // Initialize an object, ref count == 1 PushButton button = PushButton::New(); @@ -208,7 +208,7 @@ int UtcDaliPushButtonMoveConstructor(void) int UtcDaliPushButtonAssignmentOperatorP(void) { - TestApplication application; + ToolkitTestApplication application; PushButton button = PushButton::New(); @@ -241,7 +241,7 @@ int UtcDaliPushButtonMoveAssignment(void) int UtcDaliPushButtonNewP(void) { - TestApplication application; + ToolkitTestApplication application; PushButton button = PushButton::New(); @@ -251,7 +251,7 @@ int UtcDaliPushButtonNewP(void) int UtcDaliPushButtonDownCastP(void) { - TestApplication application; + ToolkitTestApplication application; PushButton button = PushButton::New(); @@ -267,7 +267,7 @@ int UtcDaliPushButtonDownCastP(void) int UtcDaliPushButtonDownCastN(void) { - TestApplication application; + ToolkitTestApplication application; BaseHandle unInitializedObject; diff --git a/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp index ee1ebf5..6062415 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-RadioButton.cpp @@ -66,7 +66,7 @@ static std::string GetButtonText( Button button ) int UtcDaliRadioButtonConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; RadioButton button; @@ -76,7 +76,7 @@ int UtcDaliRadioButtonConstructorP(void) int UtcDaliRadioButtonCopyConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; // Initialize an object, ref count == 1 RadioButton button = RadioButton::New(); @@ -107,7 +107,7 @@ int UtcDaliRadioButtonMoveConstructor(void) int UtcDaliRadioButtonAssignmentOperatorP(void) { - TestApplication application; + ToolkitTestApplication application; RadioButton button = RadioButton::New(); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp index 5d49b98..1105c73 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-Scene3dView.cpp @@ -75,7 +75,7 @@ const char* TEST_SPECULAR_TEXTURE = TEST_RESOURCE_DIR "/forest_specular_cubemap. int UtcDaliScene3dViewConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; Scene3dView scene3dView; @@ -85,7 +85,7 @@ int UtcDaliScene3dViewConstructorP(void) int UtcDaliScene3dViewCopyConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; // Initialize an object, ref count == 1 Scene3dView scene3dView = Scene3dView::New( TEST_GLTF_FILE_NAME[0] ); @@ -97,7 +97,7 @@ int UtcDaliScene3dViewCopyConstructorP(void) int UtcDaliScene3dViewCopyConstructor2P(void) { - TestApplication application; + ToolkitTestApplication application; // Initialize an object, ref count == 1 Toolkit::Scene3dView scene3dView = Toolkit::Scene3dView::New( TEST_GLTF_FILE_NAME[0], TEST_DIFFUSE_TEXTURE, TEST_SPECULAR_TEXTURE, Vector4::ONE ); @@ -109,7 +109,7 @@ int UtcDaliScene3dViewCopyConstructor2P(void) int UtcDaliScene3dViewAssignmentOperatorP(void) { - TestApplication application; + ToolkitTestApplication application; Scene3dView scene3dView = Scene3dView::New( TEST_GLTF_FILE_NAME[0] ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp index 7c6dece..1a540a2 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-TableView.cpp @@ -93,7 +93,7 @@ static void SetupTableViewAndActors(Integration::Scene scene, TableView& tableVi int UtcDaliTableViewCtorCopyP(void) { - TestApplication application; + ToolkitTestApplication application; TableView actor1 = TableView::New(10,10); TableView actor2( actor1 ); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp b/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp index 90635df..6d3424e 100644 --- a/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp +++ b/automated-tests/src/dali-toolkit/utc-Dali-ToggleButton.cpp @@ -74,7 +74,7 @@ Dali::Integration::Point GetPointUpInside() int UtcDaliToggleButtonConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; tet_infoline(" UtcDaliToggleButtonConstructorP"); ToggleButton button; @@ -84,7 +84,7 @@ int UtcDaliToggleButtonConstructorP(void) int UtcDaliToggleButtonCopyConstructorP(void) { - TestApplication application; + ToolkitTestApplication application; tet_infoline(" UtcDaliToggleButtonCopyConstructorP"); // Initialize an object, ref count == 1 @@ -97,7 +97,7 @@ int UtcDaliToggleButtonCopyConstructorP(void) int UtcDaliToggleButtonAssignmentOperatorP(void) { - TestApplication application; + ToolkitTestApplication application; tet_infoline(" UtcDaliToggleButtonAssignmentOperatorP"); ToggleButton button = ToggleButton::New(); diff --git a/dali-toolkit/devel-api/accessibility-manager/accessibility-manager.cpp b/dali-toolkit/devel-api/accessibility-manager/accessibility-manager.cpp index 99e2199..b7f6892 100644 --- a/dali-toolkit/devel-api/accessibility-manager/accessibility-manager.cpp +++ b/dali-toolkit/devel-api/accessibility-manager/accessibility-manager.cpp @@ -57,7 +57,6 @@ AccessibilityManager AccessibilityManager::Get() // If not, create the accessibility manager and register it as a singleton Internal::AccessibilityManager* internalManager = new Internal::AccessibilityManager(); manager = AccessibilityManager(internalManager); - internalManager->Initialise(); singletonService.Register(typeid(manager), manager); } } diff --git a/dali-toolkit/devel-api/controls/control-devel.cpp b/dali-toolkit/devel-api/controls/control-devel.cpp index 053e4de..a855b2d 100644 --- a/dali-toolkit/devel-api/controls/control-devel.cpp +++ b/dali-toolkit/devel-api/controls/control-devel.cpp @@ -19,11 +19,13 @@ #include "control-devel.h" // EXTERNAL INCLUDES +#include #include // INTERNAL INCLUDES #include #include +#include #include namespace Dali @@ -113,6 +115,232 @@ VisualEventSignalType& VisualEventSignal(Control control) return controlDataImpl.VisualEventSignal(); } +static Toolkit::Internal::Control::Impl *GetControlImplementationIfAny( Dali::Actor actor) +{ + Dali::Toolkit::Control c = Toolkit::Control::DownCast( actor ); + if ( c ) + { + auto &impl1 = Toolkit::Internal::GetImplementation( c ); + auto &impl2 = Toolkit::Internal::Control::Impl::Get( impl1 ); + return &impl2; + } + return nullptr; +} + +Toolkit::DevelControl::AccessibilityActivateSignalType &AccessibilityActivateSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityActivateSignal; +} + +Toolkit::DevelControl::AccessibilityReadingSkippedSignalType &AccessibilityReadingSkippedSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityReadingSkippedSignal; +} + +Toolkit::DevelControl::AccessibilityReadingPausedSignalType &AccessibilityReadingPausedSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityReadingPausedSignal; +} + +Toolkit::DevelControl::AccessibilityReadingResumedSignalType &AccessibilityReadingResumedSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityReadingResumedSignal; +} + +Toolkit::DevelControl::AccessibilityReadingCancelledSignalType &AccessibilityReadingCancelledSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityReadingCancelledSignal; +} + +Toolkit::DevelControl::AccessibilityReadingStoppedSignalType &AccessibilityReadingStoppedSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityReadingStoppedSignal; +} + +Toolkit::DevelControl::AccessibilityGetNameSignalType &AccessibilityGetNameSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityGetNameSignal; +} + +Toolkit::DevelControl::AccessibilityGetDescriptionSignalType &AccessibilityGetDescriptionSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityGetDescriptionSignal; +} + +Toolkit::DevelControl::AccessibilityDoGestureSignalType &AccessibilityDoGestureSignal( Toolkit::Control control ) +{ + auto ac = GetControlImplementationIfAny ( control ); + return ac->mAccessibilityDoGestureSignal; +} + +void AppendAccessibilityRelation( Dali::Actor control, Actor destination, Dali::Accessibility::RelationType relation) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + auto index = static_cast(relation); + if (index >= ac->mAccessibilityRelations.size()) + { + DALI_LOG_ERROR( "Relation index exceeds vector size." ); + return; + } + + auto obj = ac->GetAccessibilityObject(destination); + if (obj) + ac->mAccessibilityRelations[index].push_back(obj->GetAddress()); + } +} + +void RemoveAccessibilityRelation( Dali::Actor control, Actor destination, Dali::Accessibility::RelationType relation) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + auto index = static_cast(relation); + if (index >= ac->mAccessibilityRelations.size()) + { + DALI_LOG_ERROR( "Relation index exceeds vector size." ); + return; + } + + auto obj = ac->GetAccessibilityObject(destination); + if (!obj) + return; + + auto address = obj->GetAddress(); + + auto &targets = ac->mAccessibilityRelations[index]; + for (auto i = 0u; i < targets.size(); ++i) { + if (targets[i].ToString() == address.ToString()) + { + targets[i] = targets.back(); + targets.erase(targets.end() - 1); + } + } + } +} + +std::vector> GetAccessibilityRelations( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + return ac->mAccessibilityRelations; + } + return {}; +} + +void ClearAccessibilityRelations( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + for (auto &it : ac->mAccessibilityRelations) + it.clear(); + } +} + +void SetAccessibilityConstructor( Dali::Actor control, + std::function< std::unique_ptr< Dali::Accessibility::Accessible >( Dali::Actor ) > constructor ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->accessibilityConstructor = constructor; + } +} + +void AppendAccessibilityAttribute( Dali::Actor control, const std::string& key, + const std::string value ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->AppendAccessibilityAttribute( key, value ); + } +} + +void RemoveAccessibilityAttribute( Dali::Actor control, const std::string& key ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->RemoveAccessibilityAttribute( key ); + } +} + +void ClearAccessibilityAttributes( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->ClearAccessibilityAttributes(); + } +} + +void SetAccessibilityReadingInfoType( Dali::Actor control, const Dali::Accessibility::ReadingInfoTypes types ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->SetAccessibilityReadingInfoType( types ); + } +} + +Dali::Accessibility::ReadingInfoTypes GetAccessibilityReadingInfoType(Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + return ac->GetAccessibilityReadingInfoType(); + } + return {}; +} + +bool ClearAccessibilityHighlight( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + auto ptr = dynamic_cast( ac->GetAccessibilityObject() ); + if( ptr ) + return ptr->ClearHighlight(); + } + return false; +} + +bool GrabAccessibilityHighlight( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + auto ptr = dynamic_cast( ac->GetAccessibilityObject() ); + if( ptr ) + return ptr->GrabHighlight(); + } + return false; +} + +Dali::Accessibility::States GetAccessibilityStates( Dali::Actor control ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + auto ptr = dynamic_cast( ac->GetAccessibilityObject() ); + if(ptr) + return ptr->GetStates(); + } + return {}; +} + +void NotifyAccessibilityStateChange( Dali::Actor control, Dali::Accessibility::States states, bool doRecursive ) +{ + if ( auto ac = GetControlImplementationIfAny ( control ) ) + { + ac->GetAccessibilityObject()->NotifyAccessibilityStateChange( std::move(states), doRecursive ); + } +} + +Dali::Accessibility::Accessible *GetBoundAccessibilityObject( Dali::Actor control ) +{ + return Dali::Accessibility::Accessible::Get( control ); +} + } // namespace DevelControl } // namespace Toolkit diff --git a/dali-toolkit/devel-api/controls/control-devel.h b/dali-toolkit/devel-api/controls/control-devel.h index da4b730..5753a69 100644 --- a/dali-toolkit/devel-api/controls/control-devel.h +++ b/dali-toolkit/devel-api/controls/control-devel.h @@ -18,6 +18,7 @@ * */ // EXTERNAL INCLUDES +#include #include // INTERNAL INCLUDES @@ -37,6 +38,33 @@ class Base; namespace DevelControl { +/// @brief AccessibilityActivate signal type. +typedef Signal< void ( ) > AccessibilityActivateSignalType; + +/// @brief AccessibilityReadingSkipped signal type. +typedef Signal< void ( ) > AccessibilityReadingSkippedSignalType; + +/// @brief AccessibilityReadingPaused signal type. +typedef Signal< void ( ) > AccessibilityReadingPausedSignalType; + +/// @brief AccessibilityReadingResumed signal type. +typedef Signal< void ( ) > AccessibilityReadingResumedSignalType; + +/// @brief AccessibilityReadingCancelled signal type. +typedef Signal< void ( ) > AccessibilityReadingCancelledSignalType; + +/// @brief AccessibilityReadingStopped signal type. +typedef Signal< void ( ) > AccessibilityReadingStoppedSignalType; + +/// @brief AccessibilityGetName signal type. +typedef Signal< void ( std::string& ) > AccessibilityGetNameSignalType; + +/// @brief AccessibilityGetDescription signal type. +typedef Signal< void ( std::string& ) > AccessibilityGetDescriptionSignalType; + +/// @brief AccessibilityDoGesture signal type. +typedef Signal< void ( std::pair& ) > AccessibilityDoGestureSignalType; + enum State { NORMAL, @@ -115,7 +143,52 @@ enum * @brief The shadow of the control. * @details Name "shadow", type Property::MAP. */ - SHADOW = PADDING + 8 + SHADOW = PADDING + 8, + + /** + * @brief The name of object visible in accessibility tree. + * @details Name "accessibilityName", type Property::STRING. + */ + ACCESSIBILITY_NAME, + + /** + * @brief The description of object visible in accessibility tree. + * @details Name "accessibilityDescription", type Property::STRING. + */ + ACCESSIBILITY_DESCRIPTION, + + /** + * @brief Current translation domain for accessibility clients. + * @details Name "accessibilityTranslationDomain", type Property::STRING. + */ + ACCESSIBILITY_TRANSLATION_DOMAIN, + + /** + * @brief Role being performed in accessibility hierarchy. + * @details Name "accessibilityRole", type Property::INTEGER. + * @note Property is stored as INTEGER, however its interpretaton + * depend on enumeration Dali::Accessibility::Role and should be read and written + * with usage of enumerated values. + * @see Dali::Accessibility::Role + */ + ACCESSIBILITY_ROLE, + /** + * @brief Mark of able to highlight object. + * @details Name "accessibilityHighlightable", type Property::BOOLEAN. + */ + ACCESSIBILITY_HIGHLIGHTABLE, + /** + * @brief Set of accessibility attributes describing object in accessibility hierarchy + * @details Name "accessibilityAttributes", type Property::MAP + */ + ACCESSIBILITY_ATTRIBUTES, + + /** + * @brief Boolean flag describing object as animated + * @details Name "accessibilityAnimated", type Property::BOOLEAN + * @note Flag set to true will prevent BoundChanged accessibility signal from emiting + */ + ACCESSIBILITY_ANIMATED }; } // namespace Property @@ -284,6 +357,214 @@ using VisualEventSignalType = Signal> GetAccessibilityRelations( Dali::Actor control ); + +/** + * @brief The method removes all previously appended relations + * + * @param control object to append attribute to + */ +DALI_TOOLKIT_API void ClearAccessibilityRelations( Dali::Actor control ); + +/** + * @brief The method allows to add or modify value matched with given key. + * Modification take place if key was previously set. + * + * @param control object to append attribute to + * @param key std::string value + * @param value std::string value + */ +DALI_TOOLKIT_API void AppendAccessibilityAttribute( Dali::Actor control, const std::string& key, const std::string value ); + +/** + * @brief The method erases key with its value from accessibility attributes + * @param control object to append attribute to + * @param key std::string value + */ +DALI_TOOLKIT_API void RemoveAccessibilityAttribute( Dali::Actor control, const std::string& key ); + +/** + * @brief The method clears accessibility attributes + * + * @param control object to append attribute to + */ +DALI_TOOLKIT_API void ClearAccessibilityAttributes( Dali::Actor control ); + +/** + * @brief The method inserts reading information of an accessible object into attributes + * + * @param control object to append attribute to + * @param types Reading information types + */ +DALI_TOOLKIT_API void SetAccessibilityReadingInfoType( Dali::Actor control, const Dali::Accessibility::ReadingInfoTypes types ); + +/** + * @brief The method returns reading information of an accessible object + * + * @param control object to append attribute to + * @return Reading information types + */ +DALI_TOOLKIT_API Dali::Accessibility::ReadingInfoTypes GetAccessibilityReadingInfoType( Dali::Actor control ); + +/** + * @brief The method erases highlight. + * + * @param control object to append attribute to + * @return bool value, false when it is not possible or something went wrong, at the other way true. + */ +DALI_TOOLKIT_API bool ClearAccessibilityHighlight( Dali::Actor control ); + +/** + * @brief The method grabs highlight. + * + * @param control object to append attribute to + * @return bool value, false when it is not possible or something went wrong, at the other way true. + */ +DALI_TOOLKIT_API bool GrabAccessibilityHighlight( Dali::Actor control ); + +/** + * @brief The metod presents bitset of control's states. + * + * @param control object to append attribute to + * @return Dali::Accessibility::States is vector of enumerated State. + */ +DALI_TOOLKIT_API Dali::Accessibility::States GetAccessibilityStates( Dali::Actor control ); + +/** + * @brief The method force sending notifications about current states to accessibility clients + * + * @param control object to append attribute to + * @param states mask with states expected to broadcast + * @param doRecursive flag pointing if notifications of children's state would be sent + */ +DALI_TOOLKIT_API void NotifyAccessibilityStateChange( Dali::Actor control, Dali::Accessibility::States states, bool doRecursive ); + +/** + * The method allows to set specific constructor for creating accessibility structure + * + * Thank to this method hierarchy of accessibility objects can be based on internal hierarchy of Actors. + * It prevents from necessity of keeping two trees synchronized. + * The method should be called inside OnInitialize method of all classes inheriting from Control. + * + * Possible usage can be as follows: + * @code + * SetAccessibilityConstructor( []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::DIALOG, true ) ); + } ); + * @endcode + * + * param constructor callback creating Accessible object + */ +DALI_TOOLKIT_API void SetAccessibilityConstructor( Dali::Actor control, std::function(Dali::Actor)> constructor); + +/** + * Returns accessibility object bound to actor, if any + * + * This method won't bound new accessibility object. Use Dali::Accessibility::Accessible::Get in that case. + */ +DALI_TOOLKIT_API Dali::Accessibility::Accessible *GetBoundAccessibilityObject( Dali::Actor control ); + } // namespace DevelControl } // namespace Toolkit diff --git a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp index e336eee..80a6865 100644 --- a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp +++ b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.cpp @@ -19,20 +19,13 @@ #include "accessibility-manager-impl.h" // EXTERNAL INCLUDES -#include // for strcmp -#include -#include -#include -#include -#include -#include -#include +#include +#include // INTERNAL INCLUDES -#include #include #include -#include +#include namespace Dali { @@ -43,365 +36,113 @@ namespace Toolkit namespace Internal { -namespace // unnamed namespace -{ - -// Signals - -const char* const SIGNAL_FOCUS_CHANGED = "focusChanged"; -const char* const SIGNAL_FOCUS_OVERSHOT = "focusOvershot"; -const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focusedActorActivated"; - -#if defined(DEBUG_ENABLED) -Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER"); -#endif - -const char* const ACTOR_FOCUSABLE("focusable"); -const char* const IS_FOCUS_GROUP("isFocusGroup"); - -const char* FOCUS_BORDER_IMAGE_FILE_NAME = "B16-8_TTS_focus.9.png"; - -const char* FOCUS_SOUND_FILE_NAME = "Focus.ogg"; -const char* FOCUS_CHAIN_END_SOUND_FILE_NAME = "End_of_List.ogg"; - -/** - * The function to be used in the hit-test algorithm to check whether the actor is hittable. - */ -bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type) -{ - bool hittable = false; - - switch (type) - { - case Dali::HitTestAlgorithm::CHECK_ACTOR: - { - // Check whether the actor is visible and not fully transparent. - if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) - && actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f) // not FULLY_TRANSPARENT - { - // Check whether the actor is focusable - Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE); - if(propertyActorFocusable != Property::INVALID_INDEX) - { - hittable = actor.GetProperty(propertyActorFocusable); - } - } - break; - } - case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE: - { - if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) ) // Actor is visible, if not visible then none of its children are visible. - { - hittable = true; - } - break; - } - default: - { - break; - } - } - - return hittable; -}; - -} - AccessibilityManager::AccessibilityManager() -: mCurrentFocusActor(FocusIDPair(0, 0)), - mCurrentGesturedActor(), - mFocusIndicatorActor(), - mPreviousPosition( 0.0f, 0.0f ), - mRecursiveFocusMoveCounter(0), - mFocusSoundFilePath(), - mFocusChainEndSoundFilePath(), - mIsWrapped(false), - mIsFocusWithinGroup(false), - mIsEndcapFeedbackEnabled(false), - mIsEndcapFeedbackPlayed(false), - mIsAccessibilityTtsEnabled(false), - mTtsCreated(false), - mIsFocusIndicatorEnabled(false), - mContinuousPlayMode(false), - mIsFocusSoundFilePathSet(false), - mIsFocusChainEndSoundFilePathSet(false) { + mFocusOrder.push_back( {} ); // zero has a special meaning } AccessibilityManager::~AccessibilityManager() { } -void AccessibilityManager::Initialise() -{ - AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get(); - adaptor.SetActionHandler(*this); - adaptor.SetGestureHandler(*this); - - ChangeAccessibilityStatus(); -} - -AccessibilityManager::ActorAdditionalInfo AccessibilityManager::GetActorAdditionalInfo(const unsigned int actorID) const -{ - ActorAdditionalInfo data; - IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID); - if(iter != mIDAdditionalInfoContainer.end()) - { - data = (*iter).second; - } - - return data; -} - -void AccessibilityManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order) -{ - ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID); - actorInfo.mFocusOrder = order; - mIDAdditionalInfoContainer.erase(actorID); - mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo)); -} - void AccessibilityManager::SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text) { - if(actor) + switch ( type ) { - unsigned int actorID = actor.GetProperty< int >( Actor::Property::ID ); + case Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL: + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_NAME, text ); + break; - ActorAdditionalInfo info = GetActorAdditionalInfo(actorID); - info.mAccessibilityAttributes[type] = text; + case Toolkit::AccessibilityManager::ACCESSIBILITY_HINT: + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION, text ); + break; - mIDAdditionalInfoContainer.erase(actorID); - mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info)); + case Toolkit::AccessibilityManager::ACCESSIBILITY_TRAIT: + case Toolkit::AccessibilityManager::ACCESSIBILITY_VALUE: + default: + break; } } std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const { - std::string text; - - if(actor) + switch ( type ) { - ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID )); - text = data.mAccessibilityAttributes[type]; - } + case Toolkit::AccessibilityManager::ACCESSIBILITY_LABEL: + return actor.GetProperty< std::string >( Toolkit::DevelControl::Property::ACCESSIBILITY_NAME ); + + case Toolkit::AccessibilityManager::ACCESSIBILITY_HINT: + return actor.GetProperty< std::string >( Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION ); - return text; + case Toolkit::AccessibilityManager::ACCESSIBILITY_TRAIT: + case Toolkit::AccessibilityManager::ACCESSIBILITY_VALUE: + default: + return ""; + } } void AccessibilityManager::SetFocusOrder(Actor actor, const unsigned int order) { - // Do nothing if the focus order of the actor is not changed. - if(actor && GetFocusOrder(actor) != order) - { - // Firstly delete the actor from the focus chain if it's already there with a different focus order. - mFocusIDContainer.erase(GetFocusOrder(actor)); - - // Create/retrieve actor focusable property - Property::Index propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE ); - - if(order == 0) - { - // The actor is not focusable without a defined focus order. - actor.SetProperty(propertyActorFocusable, false); - - // If the actor is currently being focused, it should clear the focus - if(actor == GetCurrentFocusActor()) - { - ClearFocus(); - } - } - else // Insert the actor to the focus chain - { - // Check whether there is another actor in the focus chain with the same focus order already. - FocusIDIter focusIDIter = mFocusIDContainer.find(order); - if(focusIDIter != mFocusIDContainer.end()) - { - // We need to increase the focus order of that actor and all the actors followed it - // in the focus chain. - FocusIDIter lastIter = mFocusIDContainer.end(); - --lastIter;//We want forward iterator to the last element here - mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second)); - - // Update the actor's focus order in its additional data - SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1); - - for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--) - { - FocusIDIter previousIter = iter; - --previousIter;//We want forward iterator to the previous element here - unsigned int actorID = (*previousIter).second; - (*iter).second = actorID; + if (order == 0) + return; - // Update the actor's focus order in its additional data - SynchronizeActorAdditionalInfo(actorID, (*iter).first); - } + if (order >= mFocusOrder.size()) + mFocusOrder.resize(order + 1); - mFocusIDContainer.erase(order); - } + auto it = mFocusOrder.begin() + order; + mFocusOrder.insert(it, actor); - // The actor is focusable - actor.SetProperty(propertyActorFocusable, true); - - // Now we insert the actor into the focus chain with the specified focus order - mFocusIDContainer.insert(FocusIDPair(order, actor.GetProperty< int >( Actor::Property::ID ))); - } + if (order > 0) + { + Actor prev = mFocusOrder[order - 1]; + DevelControl::AppendAccessibilityRelation( prev, actor, Accessibility::RelationType::FLOWS_TO ); + DevelControl::AppendAccessibilityRelation( actor, prev, Accessibility::RelationType::FLOWS_FROM ); + } - // Update the actor's focus order in its additional data - SynchronizeActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID ), order); + if (order + 1 < mFocusOrder.size()) + { + Actor next = mFocusOrder[order + 1]; + DevelControl::AppendAccessibilityRelation( actor, next, Accessibility::RelationType::FLOWS_TO ); + DevelControl::AppendAccessibilityRelation( next, actor, Accessibility::RelationType::FLOWS_FROM ); } } unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const { - unsigned int focusOrder = 0; - - if(actor) + for (auto it = mFocusOrder.begin(); it != mFocusOrder.end(); ++it) { - ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID )); - focusOrder = data.mFocusOrder; + if (actor == *it) + return it - mFocusOrder.begin(); } - return focusOrder; + return 0; } unsigned int AccessibilityManager::GenerateNewFocusOrder() const { - unsigned int order = 1; - FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin(); - - if(iter != mFocusIDContainer.rend()) - { - order = (*iter).first + 1; - } - - return order; + return static_cast(mFocusOrder.size()); } Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order) { - Actor actor = Actor(); + Actor actor; - FocusIDIter focusIDIter = mFocusIDContainer.find(order); - if(focusIDIter != mFocusIDContainer.end()) - { - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - actor = rootActor.FindChildById(mFocusIDContainer[order]); - } + if (order > 0 && order < mFocusOrder.size()) + actor = mFocusOrder[order]; return actor; } bool AccessibilityManager::SetCurrentFocusActor(Actor actor) { - if(actor) - { - return DoSetCurrentFocusActor(actor.GetProperty< int >( Actor::Property::ID )); - } - - return false; -} - -bool AccessibilityManager::DoSetCurrentFocusActor(const unsigned int actorID) -{ - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - - // If the group mode is enabled, check which focus group the current focused actor belongs to - Actor focusGroup; - if(mIsFocusWithinGroup) - { - focusGroup = GetFocusGroup(GetCurrentFocusActor()); - } + Dali::Accessibility::Accessible::SetCurrentlyHighlightedActor(actor); - if(!focusGroup) - { - focusGroup = rootActor; - } - - Actor actor = focusGroup.FindChildById(actorID); - - // Check whether the actor is in the stage - if(actor) - { - // Check whether the actor is focusable - bool actorFocusable = false; - Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE); - if(propertyActorFocusable != Property::INVALID_INDEX) - { - actorFocusable = actor.GetProperty(propertyActorFocusable); - } - - // Go through the actor's hierarchy to check whether the actor is visible - bool actorVisible = actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ); - Actor parent = actor.GetParent(); - while (actorVisible && parent && parent != rootActor) - { - actorVisible = parent.GetCurrentProperty< bool >( Actor::Property::VISIBLE ); - parent = parent.GetParent(); - } - - // Check whether the actor is fully transparent - bool actorOpaque = actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f; - - // Set the focus only when the actor is focusable and visible and not fully transparent - if(actorVisible && actorFocusable && actorOpaque) - { - // Draw the focus indicator upon the focused actor - if( mIsFocusIndicatorEnabled ) - { - actor.Add( GetFocusIndicatorActor() ); - } - - // Send notification for the change of focus actor - mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor ); - - // Save the current focused actor - mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID); - - if(mIsAccessibilityTtsEnabled) - { - Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get(); - if(soundPlayer) - { - if (!mIsFocusSoundFilePathSet) - { - const std::string soundDirPath = AssetManager::GetDaliSoundPath(); - mFocusSoundFilePath = soundDirPath + FOCUS_SOUND_FILE_NAME; - mIsFocusSoundFilePathSet = true; - } - soundPlayer.PlaySound(mFocusSoundFilePath); - } - - // Play the accessibility attributes with the TTS player. - Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER); - - // Combine attribute texts to one text - std::string informationText; - for(int i = 0; i < Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++) - { - if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty()) - { - if( i > 0 ) - { - informationText += ", "; // for space time between each information - } - informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i]; - } - } - player.Play(informationText); - } - - return true; - } - } - - DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__); - return false; + return true; } Actor AccessibilityManager::GetCurrentFocusActor() { - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - return rootActor.FindChildById(mCurrentFocusActor.second); + return Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor(); } Actor AccessibilityManager::GetCurrentFocusGroup() @@ -411,971 +152,103 @@ Actor AccessibilityManager::GetCurrentFocusGroup() unsigned int AccessibilityManager::GetCurrentFocusOrder() { - return mCurrentFocusActor.first; + auto actor = GetCurrentFocusActor(); + unsigned order = 0; + + if (actor) + order = GetFocusOrder( actor ); + + return order; } bool AccessibilityManager::MoveFocusForward() { - bool ret = false; - mRecursiveFocusMoveCounter = 0; + unsigned current = GetCurrentFocusOrder(); - FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first); - if(focusIDIter != mFocusIDContainer.end()) - { - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first); - ret = DoMoveFocus(focusIDIter, true, mIsWrapped); - } - else - { - // TODO: if there is not focused actor, move first actor - if(!mFocusIDContainer.empty()) - { - //if there is not focused actor, move 1st actor - focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted. - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first); - ret = DoSetCurrentFocusActor((*focusIDIter).second); - } - } + if (current + 1 < mFocusOrder.size()) + return SetCurrentFocusActor(mFocusOrder[current + 1]); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!"); - - return ret; + return false; } bool AccessibilityManager::MoveFocusBackward() { - bool ret = false; - mRecursiveFocusMoveCounter = 0; - - FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first); - if(focusIDIter != mFocusIDContainer.end()) - { - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first); - ret = DoMoveFocus(focusIDIter, false, mIsWrapped); - } - else - { - // TODO: if there is not focused actor, move last actor - if(!mFocusIDContainer.empty()) - { - //if there is not focused actor, move last actor - focusIDIter = mFocusIDContainer.end(); - --focusIDIter;//We want forward iterator to the last element here - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first); - ret = DoSetCurrentFocusActor((*focusIDIter).second); - } - } + unsigned current = GetCurrentFocusOrder(); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!"); + if (current > 1) // zero has a special meaning + return SetCurrentFocusActor(mFocusOrder[current - 1]); - return ret; + return false; } -void AccessibilityManager::DoActivate(Actor actor) +void AccessibilityManager::ClearFocus() { - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // Notify the control that it is activated - GetImplementation( control ).AccessibilityActivate(); - } - - // Send notification for the activation of focused actor - mFocusedActorActivatedSignal.Emit(actor); - } + auto actor = GetCurrentFocusActor(); + Toolkit::DevelControl::ClearAccessibilityHighlight( actor ); } -void AccessibilityManager::ClearFocus() +void AccessibilityManager::Reset() { - Actor actor = GetCurrentFocusActor(); - if( actor && mFocusIndicatorActor ) - { - actor.Remove( mFocusIndicatorActor ); - } - - mCurrentFocusActor = FocusIDPair(0, 0); - - // Send notification for the change of focus actor - mFocusChangedSignal.Emit(actor, Actor()); + ClearFocus(); - if(mIsAccessibilityTtsEnabled) + for (std::size_t i = 2; i < mFocusOrder.size(); ++i) { - // Stop the TTS playing if any - Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER); - player.Stop(); + Actor prev = mFocusOrder[i - 1]; + Actor next = mFocusOrder[i]; + + DevelControl::RemoveAccessibilityRelation( prev, next, Accessibility::RelationType::FLOWS_TO ); + DevelControl::RemoveAccessibilityRelation( next, prev, Accessibility::RelationType::FLOWS_FROM ); } -} -void AccessibilityManager::Reset() -{ - ClearFocus(); - mFocusIDContainer.clear(); - mIDAdditionalInfoContainer.clear(); + mFocusOrder.clear(); + mFocusOrder.push_back( {} ); } void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup) { - if(actor) - { - // Create/Set focus group property. - actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE ); - } } bool AccessibilityManager::IsFocusGroup(Actor actor) const { - // Check whether the actor is a focus group - bool isFocusGroup = false; - - if(actor) - { - Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP); - if(propertyIsFocusGroup != Property::INVALID_INDEX) - { - isFocusGroup = actor.GetProperty(propertyIsFocusGroup); - } - } - - return isFocusGroup; + return false; } Actor AccessibilityManager::GetFocusGroup(Actor actor) { - // Go through the actor's hierarchy to check which focus group the actor belongs to - while (actor && !IsFocusGroup(actor)) - { - actor = actor.GetParent(); - } - - return actor; + return {}; } Vector2 AccessibilityManager::GetReadPosition() const { - AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get(); - return adaptor.GetReadPosition(); + return {}; } void AccessibilityManager::SetGroupMode(bool enabled) { - mIsFocusWithinGroup = enabled; } bool AccessibilityManager::GetGroupMode() const { - return mIsFocusWithinGroup; + return false; } void AccessibilityManager::SetWrapMode(bool wrapped) { - mIsWrapped = wrapped; } bool AccessibilityManager::GetWrapMode() const { - return mIsWrapped; + return true; } void AccessibilityManager::SetFocusIndicatorActor(Actor indicator) { - if( mFocusIndicatorActor != indicator ) - { - Actor currentFocusActor = GetCurrentFocusActor(); - if( currentFocusActor ) - { - // The new focus indicator should be added to the current focused actor immediately - if( mFocusIndicatorActor ) - { - currentFocusActor.Remove( mFocusIndicatorActor ); - } - - if( indicator ) - { - currentFocusActor.Add( indicator ); - } - } - - mFocusIndicatorActor = indicator; - } + Dali::Accessibility::Accessible::SetHighlightActor( indicator ); } Actor AccessibilityManager::GetFocusIndicatorActor() { - if( ! mFocusIndicatorActor ) - { - // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors - const std::string imageDirPath = AssetManager::GetDaliImagePath(); - const std::string focusBorderImagePath = imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME; - - mFocusIndicatorActor = Toolkit::ImageView::New(focusBorderImagePath); - mFocusIndicatorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER ); - mFocusIndicatorActor.SetProperty( Actor::Property::POSITION_Z, 1.0f ); - - // Apply size constraint to the focus indicator - mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); - } - - return mFocusIndicatorActor; -} - -bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped) -{ - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size()); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first); - - if( (forward && ++focusIDIter == mFocusIDContainer.end()) - || (!forward && focusIDIter-- == mFocusIDContainer.begin()) ) - { - if(mIsEndcapFeedbackEnabled) - { - if(mIsEndcapFeedbackPlayed == false) - { - // play sound & skip moving once - Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get(); - if(soundPlayer) - { - if (!mIsFocusChainEndSoundFilePathSet) - { - const std::string soundDirPath = AssetManager::GetDaliSoundPath(); - mFocusChainEndSoundFilePath = soundDirPath + FOCUS_CHAIN_END_SOUND_FILE_NAME; - mIsFocusChainEndSoundFilePathSet = true; - } - soundPlayer.PlaySound(mFocusChainEndSoundFilePath); - } - - mIsEndcapFeedbackPlayed = true; - return true; - } - mIsEndcapFeedbackPlayed = false; - } - - if(wrapped) - { - if(forward) - { - focusIDIter = mFocusIDContainer.begin(); - } - else - { - focusIDIter = mFocusIDContainer.end(); - --focusIDIter;//We want forward iterator to the last element here - } - } - else - { - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__); - // Send notification for handling overshooted situation - mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS); - - return false; // Try to move the focus out of the scope - } - } - - // Invalid focus. - if( focusIDIter == mFocusIDContainer.end() ) - { - return false; - } - - // Note: This function performs the focus change. - if( !DoSetCurrentFocusActor( (*focusIDIter).second ) ) - { - mRecursiveFocusMoveCounter++; - if(mRecursiveFocusMoveCounter > mFocusIDContainer.size()) - { - // We've attempted to focus all the actors in the whole focus chain and no actor - // can be focused successfully. - DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter); - - return false; - } - else - { - return DoMoveFocus(focusIDIter, forward, wrapped); - } - } - - return true; -} - -void AccessibilityManager::SetFocusable(Actor actor, bool focusable) -{ - if(actor) - { - // Create/Set actor focusable property. - actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE ); - } -} - -bool AccessibilityManager::ChangeAccessibilityStatus() -{ - AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get(); - mIsAccessibilityTtsEnabled = adaptor.IsEnabled(); - Dali::Toolkit::AccessibilityManager handle( this ); - - if(mIsAccessibilityTtsEnabled) - { - // Show indicator when tts turned on if there is focused actor. - Actor actor = GetCurrentFocusActor(); - if(actor) - { - actor.Add( GetFocusIndicatorActor() ); - } - mIsFocusIndicatorEnabled = true; - - // Connect a signal to the TTS player to implement continuous reading mode. - Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER ); - player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged ); - mTtsCreated = true; - } - else - { - // Hide indicator when tts turned off - Actor actor = GetCurrentFocusActor(); - if( actor && mFocusIndicatorActor ) - { - actor.Remove( mFocusIndicatorActor ); - } - mIsFocusIndicatorEnabled = false; - - if( mTtsCreated ) - { - // Disconnect the TTS state change signal. - Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER ); - player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged ); - mTtsCreated = true; - } - } - - mStatusChangedSignal.Emit( handle ); - - return true; -} - -bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionNextSignal.Empty() ) - { - mActionNextSignal.Emit( handle ); - } - - if(mIsAccessibilityTtsEnabled) - { - mIsEndcapFeedbackEnabled = allowEndFeedback; - return MoveFocusForward(); - } - else - { - return false; - } -} - -bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionPreviousSignal.Empty() ) - { - mActionPreviousSignal.Emit( handle ); - } - - if(mIsAccessibilityTtsEnabled) - { - mIsEndcapFeedbackEnabled = allowEndFeedback; - return MoveFocusBackward(); - } - else - { - return false; - } -} - -bool AccessibilityManager::AccessibilityActionActivate() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionActivateSignal.Empty() ) - { - mActionActivateSignal.Emit( handle ); - } - - bool ret = false; - - Actor actor = GetCurrentFocusActor(); - if(actor) - { - DoActivate(actor); - ret = true; - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - - if( allowReadAgain ) - { - if ( !mActionReadSignal.Empty() ) - { - mActionReadSignal.Emit( handle ); - } - } - else - { - if ( !mActionOverSignal.Empty() ) - { - mActionOverSignal.Emit( handle ); - } - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - // Find the focusable actor at the read position - AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get(); - Dali::HitTestAlgorithm::Results results; - Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction ); - - FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor)); - if(focusIDIter != mFocusIDContainer.end()) - { - if( allowReadAgain || (results.actor != GetCurrentFocusActor()) ) - { - // Move the focus to the actor - ret = SetCurrentFocusActor(results.actor); - DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE"); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionReadNextSignal.Empty() ) - { - mActionReadNextSignal.Emit( handle ); - } - - if(mIsAccessibilityTtsEnabled) - { - return MoveFocusForward(); - } - else - { - return false; - } -} - -bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionReadPreviousSignal.Empty() ) - { - mActionReadPreviousSignal.Emit( handle ); - } - - if(mIsAccessibilityTtsEnabled) - { - return MoveFocusBackward(); - } - else - { - return false; - } -} - -bool AccessibilityManager::AccessibilityActionUp() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionUpSignal.Empty() ) - { - mActionUpSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // Notify the control that it is activated - ret = GetImplementation( control ).OnAccessibilityValueChange(true); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionDown() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionDownSignal.Empty() ) - { - mActionDownSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // Notify the control that it is activated - ret = GetImplementation( control ).OnAccessibilityValueChange(false); - } - } - } - - return ret; -} - -bool AccessibilityManager::ClearAccessibilityFocus() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionClearFocusSignal.Empty() ) - { - mActionClearFocusSignal.Emit( handle ); - } - - if(mIsAccessibilityTtsEnabled) - { - ClearFocus(); - return true; - } - else - { - return false; - } -} - -bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touch ) -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionScrollSignal.Empty() ) - { - mActionScrollSignal.Emit( handle, touch ); - } - - return true; -} - -bool AccessibilityManager::AccessibilityActionBack() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionBackSignal.Empty() ) - { - mActionBackSignal.Emit( handle ); - } - - // TODO: Back to previous view - - return mIsAccessibilityTtsEnabled; -} - -bool AccessibilityManager::AccessibilityActionScrollUp() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionScrollUpSignal.Empty() ) - { - mActionScrollUpSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll up. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionScrollDown() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionScrollDownSignal.Empty() ) - { - mActionScrollDownSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll down. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionPageLeft() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionPageLeftSignal.Empty() ) - { - mActionPageLeftSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll left to the previous page. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionPageRight() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionPageRightSignal.Empty() ) - { - mActionPageRightSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll right to the next page. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionPageUp() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionPageUpSignal.Empty() ) - { - mActionPageUpSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll up to the previous page. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionPageDown() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionPageDownSignal.Empty() ) - { - mActionPageDownSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // TODO: Notify the control to scroll down to the next page. Should control handle this? -// ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionMoveToFirst() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionMoveToFirstSignal.Empty() ) - { - mActionMoveToFirstSignal.Emit( handle ); - } - - // TODO: Move to the first item on screen - - return mIsAccessibilityTtsEnabled; -} - -bool AccessibilityManager::AccessibilityActionMoveToLast() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionMoveToLastSignal.Empty() ) - { - mActionMoveToLastSignal.Emit( handle ); - } - - // TODO: Move to the last item on screen - - return mIsAccessibilityTtsEnabled; -} - -bool AccessibilityManager::AccessibilityActionReadFromTop() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionReadFromTopSignal.Empty() ) - { - mActionReadFromTopSignal.Emit( handle ); - } - - // TODO: Move to the top item on screen and read from the item continuously - - return mIsAccessibilityTtsEnabled; -} - -bool AccessibilityManager::AccessibilityActionReadFromNext() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - - if( !mActionReadFromNextSignal.Empty() ) - { - mActionReadFromNextSignal.Emit( handle ); - } - - if( mIsAccessibilityTtsEnabled ) - { - // Mark that we are in continuous play mode, so TTS signals can move focus. - mContinuousPlayMode = true; - - // Attempt to move to the next item and read from the item continuously. - MoveFocusForward(); - } - - return mIsAccessibilityTtsEnabled; -} - -void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState ) -{ - if( mContinuousPlayMode ) - { - // If we were playing and now we have stopped, attempt to play the next item. - if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) ) - { - // Attempt to move the focus forward and play. - // If we can't cancel continuous play mode. - if( !MoveFocusForward() ) - { - // We are done, exit continuous play mode. - mContinuousPlayMode = false; - } - } - else - { - // Unexpected play state change, exit continuous play mode. - mContinuousPlayMode = false; - } - } -} - -bool AccessibilityManager::AccessibilityActionZoom() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionZoomSignal.Empty() ) - { - mActionZoomSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - Actor actor = GetCurrentFocusActor(); - if(actor) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor); - if(control) - { - // Notify the control to zoom - ret = GetImplementation( control ).OnAccessibilityZoom(); - } - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionReadPauseResume() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionReadPauseResumeSignal.Empty() ) - { - mActionReadPauseResumeSignal.Emit( handle ); - } - - bool ret = false; - - if(mIsAccessibilityTtsEnabled) - { - // Pause or resume the TTS player - Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER); - Dali::TtsPlayer::State state = player.GetState(); - if(state == Dali::TtsPlayer::PLAYING) - { - player.Pause(); - ret = true; - } - else if(state == Dali::TtsPlayer::PAUSED) - { - player.Resume(); - ret = true; - } - } - - return ret; -} - -bool AccessibilityManager::AccessibilityActionStartStop() -{ - Dali::Toolkit::AccessibilityManager handle( this ); - if( !mActionStartStopSignal.Empty() ) - { - mActionStartStopSignal.Emit( handle ); - } - - // TODO: Start/stop the current action - - return mIsAccessibilityTtsEnabled; -} - -bool AccessibilityManager::HandlePanGesture(const AccessibilityGestureEvent& panEvent) -{ - bool handled = false; - - if( panEvent.state == AccessibilityGestureEvent::STARTED ) - { - // Find the focusable actor at the event position - Dali::HitTestAlgorithm::Results results; - AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get(); - - Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction ); - mCurrentGesturedActor = results.actor; - - if(!mCurrentGesturedActor) - { - DALI_LOG_ERROR("Gesture detected, but no hit actor\n"); - } - } - - // GestureState::FINISHED (Up) events are delivered with previous (Motion) event position - // Use the real previous position; otherwise we may incorrectly get a ZERO velocity - if ( AccessibilityGestureEvent::FINISHED != panEvent.state ) - { - // Store the previous position for next GestureState::FINISHED iteration. - mPreviousPosition = panEvent.previousPosition; - } - - Actor rootActor = Stage::GetCurrent().GetRootLayer(); - - Dali::PanGesture pan = DevelPanGesture::New( static_cast(panEvent.state) ); - DevelPanGesture::SetTime( pan, panEvent.time ); - DevelPanGesture::SetNumberOfTouches( pan, panEvent.numberOfTouches ); - DevelPanGesture::SetScreenPosition( pan, panEvent.currentPosition ); - DevelPanGesture::SetScreenDisplacement( pan, mPreviousPosition - panEvent.currentPosition ); - DevelPanGesture::SetScreenVelocity( pan, Vector2( pan.GetScreenDisplacement().x / panEvent.timeDelta, pan.GetScreenDisplacement().y / panEvent.timeDelta ) ); - - // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor - while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled) - { - Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor); - if(control) - { - Vector2 localCurrent; - control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y ); - DevelPanGesture::SetPosition( pan, localCurrent ); - - Vector2 localPrevious; - control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y ); - - DevelPanGesture::SetDisplacement( pan, localCurrent - localPrevious ); - DevelPanGesture::SetVelocity( pan, Vector2( pan.GetDisplacement().x / panEvent.timeDelta, pan.GetDisplacement().y / panEvent.timeDelta )); - - handled = GetImplementation( control ).OnAccessibilityPan(pan); - } - - // If the gesture is not handled by the control, check its parent - if(!handled) - { - mCurrentGesturedActor = mCurrentGesturedActor.GetParent(); - - if(!mCurrentGesturedActor) - { - DALI_LOG_ERROR("no more gestured actor\n"); - } - } - else - { - // If handled, then update the pan gesture properties - PanGestureDetector::SetPanGestureProperties( pan ); - } - } - - return handled; + return Dali::Accessibility::Accessible::GetHighlightActor(); } Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal() diff --git a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h index 1e84bfb..b55d448 100644 --- a/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h +++ b/dali-toolkit/internal/accessibility-manager/accessibility-manager-impl.h @@ -20,15 +20,11 @@ // EXTERNAL INCLUDES #include -#include -#include -#include -#include +#include #include // INTERNAL INCLUDES #include -#include namespace Dali { @@ -44,46 +40,19 @@ class AccessibilityManager; /** * @copydoc Toolkit::AccessibilityManager */ -class AccessibilityManager : public Dali::BaseObject, Dali::AccessibilityActionHandler, Dali::AccessibilityGestureHandler, public Dali::ConnectionTracker +class AccessibilityManager : public Dali::BaseObject, public Dali::ConnectionTracker { public: typedef Dali::Toolkit::AccessibilityManager::AccessibilityActionSignalType AccessibilityActionSignalType; typedef Dali::Toolkit::AccessibilityManager::AccessibilityActionScrollSignalType AccessibilityActionScrollSignalType; - struct ActorAdditionalInfo - { - ActorAdditionalInfo() - : mFocusOrder(0) - { - } - - unsigned int mFocusOrder; ///< The focus order of the actor. It is undefined by default. - - std::string mAccessibilityAttributes[Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM]; ///< The array of attribute texts - }; - - typedef std::pair FocusIDPair; - typedef std::map FocusIDContainer; - typedef FocusIDContainer::iterator FocusIDIter; - typedef FocusIDContainer::const_iterator FocusIDConstIter; - - typedef std::pair IDAdditionalInfoPair; - typedef std::map IDAdditionalInfoContainer; - typedef IDAdditionalInfoContainer::iterator IDAdditionalInfoIter; - typedef IDAdditionalInfoContainer::const_iterator IDAdditionalInfoConstIter; - /** * Construct a new AccessibilityManager. */ AccessibilityManager(); /** - * Initialise the AccessibilityManager - */ - void Initialise(); - - /** * @copydoc Toolkit::AccessibilityManager::SetAccessibilityAttribute */ void SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text); @@ -174,6 +143,16 @@ public: bool GetGroupMode() const; /** + * @copydoc Toolkit::AccessibilityManager::GetFocusGroup + */ + Actor GetFocusGroup(Actor actor); + + /** + * @copydoc Toolkit::AccessibilityManager::GetReadPosition + */ + Vector2 GetReadPosition() const; + + /** * @copydoc Toolkit::AccessibilityManager::SetWrapMode */ void SetWrapMode(bool wrapped); @@ -193,16 +172,6 @@ public: */ Actor GetFocusIndicatorActor(); - /** - * @copydoc Toolkit::AccessibilityManager::GetFocusGroup - */ - Actor GetFocusGroup(Actor actor); - - /** - * @copydoc Toolkit::AccessibilityManager::GetReadPosition - */ - Vector2 GetReadPosition() const; - public: /** @@ -439,234 +408,6 @@ protected: private: - /** - * Get the additional information (e.g. focus order and description) of the given actor. - * @param actorID The ID of the actor to be queried - * @return The additional information of the actor - */ - ActorAdditionalInfo GetActorAdditionalInfo(const unsigned int actorID) const; - - /** - * Synchronize the actor's additional information to reflect its latest focus order - * @param actorID The ID of the actor - * @param order The focus order of the actor - * @return The additional information of the actor - */ - void SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order); - - /** - * Move the focus to the specified actor and send notification for the focus change. - * @param actorID The ID of the actor to be queried - * @return Whether the focus is successful or not - */ - bool DoSetCurrentFocusActor(const unsigned int actorID); - - /** - * Move the focus to the next actor in the focus chain towards the specified direction. - * @param focusIDIter The iterator pointing to the current focused actor - * @param forward Whether the focus movement is forward or not. The focus movement will be backward if this is false. - * @param wrapped Whether the focus shoule be moved wrapped around or not - * @return Whether the focus is successful or not - */ - bool DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped); - - /** - * Activate the actor. If the actor is control, call OnAccessibilityActivated virtual function. - * This function will emit FocusedActorActivatedSignal. - * @param actor The actor to activate - */ - void DoActivate(Actor actor); - - /** - * Set whether the actor is focusable or not. A focusable property will be registered for - * the actor if not yet. - * @param actor The actor to be focused - * @param focusable Whether the actor is focusable or not - */ - void SetFocusable(Actor actor, bool focusable); - - /** - * Handle the accessibility pan gesture. - * @param[in] panEvent The pan event to be handled. - * @return whether the gesture is handled successfully or not. - */ - bool HandlePanGesture(const AccessibilityGestureEvent& panEvent) override; - - /** - * Change the accessibility status when Accessibility feature(screen-reader) turned on or off. - * @return whether the status is changed or not. - */ - bool ChangeAccessibilityStatus() override; - - /** - * Clear the accessibility focus from the current focused actor. - * @return whether the focus is cleared or not. - */ - bool ClearAccessibilityFocus() override; - - /** - * Perform the accessibility action associated with a scroll event. - * @param touch The touch point (and time) of the event. - * @return whether the focus is cleared or not. - */ - bool AccessibilityActionScroll( Dali::TouchEvent& touch ) override; - - /** - * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick up). - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionPrevious(bool allowEndFeedback) override; - - /** - * Perform the accessibility action to move focus to the next focusable actor (by one finger flick down). - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionNext(bool allowEndFeedback) override; - - /** - * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick left). - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionReadPrevious(bool allowEndFeedback) override; - - /** - * Perform the accessibility action to move focus to the next focusable actor (by one finger flick right). - * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionReadNext(bool allowEndFeedback) override; - - /** - * Perform the accessibility action to focus and read the actor (by one finger tap or move). - * @param allowReadAgain true if the action read again the same object (i.e. read action) - * false if the action just read when the focus object is changed (i.e. over action) - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionRead(bool allowReadAgain) override; - - /** - * Perform the accessibility action to activate the current focused actor (by one finger double tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionActivate() override; - - /** - * Perform the accessibility action to change the value when the current focused actor is a slider - * (by double finger down and move up and right). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionUp() override; - - /** - * Perform the accessibility action to change the value when the current focused actor is a slider - * (by double finger down and move down and left). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionDown() override; - - /** - * Perform the accessibility action to navigate back (by two fingers circle draw). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionBack() override; - - /** - * Perform the accessibility action to scroll up the list and focus on the first item on the list - * after the scrolling and read the item (by two finger swipe up). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionScrollUp() override; - - /** - * Perform the accessibility action to scroll down the list and focus on the first item on the list - * after the scrolling and read the item (by two finger swipe down). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionScrollDown() override; - - /** - * Perform the accessibility action to scroll left to the previous page (by two finger swipe left). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionPageLeft() override; - - /** - * Perform the accessibility action to scroll right to the next page (by two finger swipe right). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionPageRight() override; - - /** - * Perform the accessibility action to scroll up to the previous page (by one finger swipe left and right). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionPageUp() override; - - /** - * Perform the accessibility action to scroll down to the next page (by one finger swipe right and left). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionPageDown() override; - - /** - * Perform the accessibility action to move the focus to the first item on the screen - * (by one finger swipe up and down). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionMoveToFirst() override; - - /** - * Perform the accessibility action to move the focus to the last item on the screen - * (by one finger swipe down and up). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionMoveToLast() override; - - /** - * Perform the accessibility action to move the focus to the first item on the top - * and read from the top item continuously (by three fingers single tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionReadFromTop() override; - - /** - * Perform the accessibility action to move the focus to and read from the next item - * continuously (by three fingers double tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionReadFromNext() override; - - /** - * Perform the accessibility action to move the focus to do the zooming (by one finger triple tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionZoom() override; - - /** - * Perform the accessibility action to pause/resume the current read out (by two fingers single tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionReadPauseResume() override; - - /** - * Perform the accessibility action to start/stop the current action (by two fingers double tap). - * @return whether the accessibility action is performed or not. - */ - bool AccessibilityActionStartStop() override; - - /** - * This function is connected to the TtsPlayer StateChangeSignal. - * It is called when the TTS players state changes. - * @param previousState The previous state of the TTS player (for comparison) - * @param currentState The current state of the TTS player - */ - void TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState ); - -private: - // Undefined AccessibilityManager(const AccessibilityManager&); @@ -674,6 +415,8 @@ private: private: + std::vector mFocusOrder; + Toolkit::AccessibilityManager::FocusChangedSignalType mFocusChangedSignal; ///< The signal to notify the focus change Toolkit::AccessibilityManager::FocusOvershotSignalType mFocusOvershotSignal; ///< The signal to notify the focus overshooted Toolkit::AccessibilityManager::FocusedActorActivatedSignalType mFocusedActorActivatedSignal; ///< The signal to notify the activation of focused actor @@ -702,31 +445,10 @@ private: AccessibilityActionSignalType mActionReadFromTopSignal; AccessibilityActionSignalType mActionReadFromNextSignal; AccessibilityActionSignalType mActionZoomSignal; + AccessibilityActionSignalType mActionReadIndicatorInformationSignal; AccessibilityActionSignalType mActionReadPauseResumeSignal; AccessibilityActionSignalType mActionStartStopSignal; AccessibilityActionScrollSignalType mActionScrollSignal; - - FocusIDContainer mFocusIDContainer; ///< The container to look up actor ID by focus order - IDAdditionalInfoContainer mIDAdditionalInfoContainer; ///< The container to look up additional information by actor ID - FocusIDPair mCurrentFocusActor; ///< The focus order and actor ID of current focused actor - Actor mCurrentGesturedActor; ///< The actor that will handle the gesture - Actor mFocusIndicatorActor; ///< The focus indicator actor shared by all the focusable actors for highlight - Vector2 mPreviousPosition; ///< The previous pan position; useful for calculating velocity for GestureState::FINISHED events - unsigned int mRecursiveFocusMoveCounter; ///< The counter to count the number of recursive focus movement attempted before the focus movement is successful. - std::string mFocusSoundFilePath; ///< The path of the focus sound file - std::string mFocusChainEndSoundFilePath; ///< The path of the focus chain end sound file - - bool mIsWrapped:1; ///< Whether the focus movement is wrapped around or not - bool mIsFocusWithinGroup:1; ///< Whether the focus movement is limited to the current focus group or not - bool mIsEndcapFeedbackEnabled:1; ///< Whether the endcap feedback need to be played when the focus leaves the end or vice versa - bool mIsEndcapFeedbackPlayed:1; ///< Whether the endcap feedback was played or not - bool mIsAccessibilityTtsEnabled:1; ///< Whether accessibility feature(screen-reader) turned on/off - bool mTtsCreated:1; ///< Whether the TTS Player has been accessed - bool mIsFocusIndicatorEnabled:1; ///< Whether indicator should be shown / hidden. It could be enabled when TTS enabled or 'Tab' key operated. - bool mContinuousPlayMode:1; ///< Keeps track of whether or not we are in continuous play mode - bool mIsFocusSoundFilePathSet:1; ///< Whether the path of the focus sound file has been set - bool mIsFocusChainEndSoundFilePathSet:1; ///< Whether the path of the focus chain end sound file has been set - }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/alignment/alignment-impl.cpp b/dali-toolkit/internal/controls/alignment/alignment-impl.cpp index 2500b0e..407eb42 100644 --- a/dali-toolkit/internal/controls/alignment/alignment-impl.cpp +++ b/dali-toolkit/internal/controls/alignment/alignment-impl.cpp @@ -24,6 +24,9 @@ #include #include +// INTERNAL INCLUDES +#include + namespace Dali { @@ -187,6 +190,14 @@ const Toolkit::Alignment::Padding& Alignment::GetPadding() const return mPadding; } +void Alignment::OnInitialize() +{ + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); +} + void Alignment::OnRelayout( const Vector2& size, RelayoutContainer& container ) { // lay out the actors diff --git a/dali-toolkit/internal/controls/alignment/alignment-impl.h b/dali-toolkit/internal/controls/alignment/alignment-impl.h index 73fe655..64d352a 100644 --- a/dali-toolkit/internal/controls/alignment/alignment-impl.h +++ b/dali-toolkit/internal/controls/alignment/alignment-impl.h @@ -21,6 +21,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -82,6 +83,11 @@ public: private: // From Control /** + * @copydoc Control::OnInitialize() + */ + virtual void OnInitialize() override; + + /** * @copydoc Control::OnRelayout() */ void OnRelayout( const Vector2& size, RelayoutContainer& container ) override; diff --git a/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp b/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp index ea1b6280..ed35267 100644 --- a/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp +++ b/dali-toolkit/internal/controls/bloom-view/bloom-view-impl.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace Dali { @@ -272,6 +273,11 @@ void BloomView::OnInitialize() // bind properties for / set shader constants to defaults SetupProperties(); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::ANIMATION ) ); + } ); } void BloomView::OnSizeSet(const Vector3& targetSize) diff --git a/dali-toolkit/internal/controls/buttons/button-impl.cpp b/dali-toolkit/internal/controls/buttons/button-impl.cpp index d840e96..b696a52 100644 --- a/dali-toolkit/internal/controls/buttons/button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/button-impl.cpp @@ -619,6 +619,7 @@ void Button::OnInitialize() mTapDetector.DetectedSignal().Connect(this, &Button::OnTap); self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true ); + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); self.TouchedSignal().Connect( this, &Button::OnTouch ); } @@ -1313,6 +1314,43 @@ Padding Button::GetForegroundPadding() return mForegroundPadding; } +std::string Button::AccessibleImpl::GetNameRaw() +{ + std::string labelText; + auto slf = Toolkit::Button::DownCast( self ); + Property::Map labelMap = slf.GetProperty( Toolkit::Button::Property::LABEL ); + + Property::Value* textPropertyPtr = labelMap.Find( Toolkit::TextVisual::Property::TEXT ); + if ( textPropertyPtr ) + { + textPropertyPtr->Get( labelText ); + } + + return labelText; +} + + +Property::Index Button::AccessibleImpl::GetNamePropertyIndex() +{ + Property::Index label = Toolkit::Button::Property::LABEL; + Property::Map labelMap = self.GetProperty(label); + + if (MapContainsTextString(labelMap)) + return label; + else + return Property::INVALID_INDEX; +} + +Dali::Accessibility::States Button::AccessibleImpl::CalculateStates() +{ + auto tmp = Control::Impl::AccessibleImpl::CalculateStates(); + tmp[Dali::Accessibility::State::SELECTABLE] = true; + auto slf = Toolkit::Button::DownCast( self ); + tmp[Dali::Accessibility::State::ENABLED] = !slf.GetProperty( Toolkit::Button::Property::DISABLED ); + tmp[Dali::Accessibility::State::CHECKED] = slf.GetProperty( Toolkit::Button::Property::SELECTED ); + return tmp; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/buttons/button-impl.h b/dali-toolkit/internal/controls/buttons/button-impl.h index 53a8890..ebe34e0 100644 --- a/dali-toolkit/internal/controls/buttons/button-impl.h +++ b/dali-toolkit/internal/controls/buttons/button-impl.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace Dali { @@ -540,6 +541,16 @@ private: // Actions bool mClickActionPerforming; ///< Used to manage signal emissions during action + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + Dali::Accessibility::States CalculateStates() override; + std::string GetNameRaw() override; + Property::Index GetNamePropertyIndex() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp b/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp index 00a99bf..103992f 100644 --- a/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/check-box-button-impl.cpp @@ -83,8 +83,32 @@ CheckBoxButton::~CheckBoxButton() void CheckBoxButton::OnInitialize() { Button::OnInitialize(); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::CHECK_BOX ) ); + } ); +} + +Dali::Accessibility::States CheckBoxButton::AccessibleImpl::CalculateStates() +{ + auto tmp = Button::AccessibleImpl::CalculateStates(); + auto slf = Toolkit::Button::DownCast( self ); + if( slf.GetProperty( Toolkit::Button::Property::SELECTED ) ) + tmp[Dali::Accessibility::State::CHECKED] = true; + return tmp; } +void CheckBoxButton::OnStateChange( State newState ) +{ + // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used + if (Dali::Accessibility::IsUp() && (newState == SELECTED_STATE || newState == UNSELECTED_STATE)) + { + Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged( + Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0 + ); + } +} } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/check-box-button-impl.h b/dali-toolkit/internal/controls/buttons/check-box-button-impl.h index 63ffbe5..531b53b 100644 --- a/dali-toolkit/internal/controls/buttons/check-box-button-impl.h +++ b/dali-toolkit/internal/controls/buttons/check-box-button-impl.h @@ -77,7 +77,14 @@ private: // Undefined CheckBoxButton& operator=( const CheckBoxButton& ); - +protected: + struct AccessibleImpl : public Button::AccessibleImpl + { + using Button::AccessibleImpl::AccessibleImpl; + + Dali::Accessibility::States CalculateStates() override; + }; + void OnStateChange( State newState ) override; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/push-button-impl.cpp b/dali-toolkit/internal/controls/buttons/push-button-impl.cpp index d09f781..2fadac4 100644 --- a/dali-toolkit/internal/controls/buttons/push-button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/push-button-impl.cpp @@ -99,6 +99,11 @@ void PushButton::OnInitialize() // Push button requires the Leave event. Actor self = Self(); self.SetProperty( Actor::Property::LEAVE_REQUIRED, true ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::PUSH_BUTTON ) ); + } ); } void PushButton::SetIconAlignment( const PushButton::IconAlignment iconAlignment ) @@ -194,6 +199,32 @@ Property::Value PushButton::GetProperty( BaseObject* object, Property::Index pro return value; } +Dali::Accessibility::States PushButton::AccessibleImpl::CalculateStates() +{ + auto tmp = Button::AccessibleImpl::CalculateStates(); + auto slf = Toolkit::Button::DownCast( self ); + tmp[Dali::Accessibility::State::PRESSED] = slf.GetProperty( Toolkit::Button::Property::SELECTED ); + return tmp; +} + +void PushButton::OnStateChange( State newState ) +{ + // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used + if (Dali::Accessibility::IsUp() && (newState == SELECTED_STATE || newState == UNSELECTED_STATE)) + { + Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged( + Dali::Accessibility::State::PRESSED, newState == SELECTED_STATE ? 1 : 0, 0 + ); + + if (Self().GetProperty(Toolkit::Button::Property::TOGGLABLE)) + { + Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged( + Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0 + ); + } + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/buttons/push-button-impl.h b/dali-toolkit/internal/controls/buttons/push-button-impl.h index a91981b..1db13d5 100644 --- a/dali-toolkit/internal/controls/buttons/push-button-impl.h +++ b/dali-toolkit/internal/controls/buttons/push-button-impl.h @@ -127,6 +127,15 @@ private: private: IconAlignment mIconAlignment; ///< The alignment of the icon against the label. + +protected: + struct AccessibleImpl : public Button::AccessibleImpl + { + using Button::AccessibleImpl::AccessibleImpl; + + Dali::Accessibility::States CalculateStates() override; + }; + void OnStateChange( State newState ) override; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp b/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp index 5389a22..3276076 100644 --- a/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/radio-button-impl.cpp @@ -75,6 +75,11 @@ RadioButton::~RadioButton() void RadioButton::OnInitialize() { Button::OnInitialize(); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::RADIO_BUTTON ) ); + } ); } bool RadioButton::OnToggleReleased() @@ -103,6 +108,23 @@ void RadioButton::OnStateChange( State newState ) } } } + // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used + if (Dali::Accessibility::IsUp() && (newState == SELECTED_STATE || newState == UNSELECTED_STATE)) + { + Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged( + Dali::Accessibility::State::CHECKED, newState == SELECTED_STATE ? 1 : 0, 0 + ); + } +} + +Dali::Accessibility::States RadioButton::AccessibleImpl::CalculateStates() +{ + auto tmp = Button::AccessibleImpl::CalculateStates(); + auto slf = Toolkit::Button::DownCast( self ); + if( slf.GetProperty( Toolkit::Button::Property::SELECTED ) ) + tmp[Dali::Accessibility::State::CHECKED] = true; + tmp[Dali::Accessibility::State::SELECTABLE] = true; + return tmp; } } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/radio-button-impl.h b/dali-toolkit/internal/controls/buttons/radio-button-impl.h index bd30c12..075f8bd 100644 --- a/dali-toolkit/internal/controls/buttons/radio-button-impl.h +++ b/dali-toolkit/internal/controls/buttons/radio-button-impl.h @@ -85,6 +85,14 @@ private: // Undefined RadioButton& operator=( const RadioButton& origin ); + +protected: + struct AccessibleImpl : public Button::AccessibleImpl + { + using Button::AccessibleImpl::AccessibleImpl; + + Dali::Accessibility::States CalculateStates() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp b/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp old mode 100755 new mode 100644 index b1808f5..a756a22 --- a/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp +++ b/dali-toolkit/internal/controls/buttons/toggle-button-impl.cpp @@ -110,6 +110,11 @@ void ToggleButton::OnInitialize() // Toggle button requires the Leave event. Actor self = Self(); self.SetProperty( Actor::Property::LEAVE_REQUIRED, true ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::TOGGLE_BUTTON ) ); + } ); } void ToggleButton::SetProperty( BaseObject* object, Property::Index propertyIndex, const Property::Value& value ) @@ -372,6 +377,45 @@ void ToggleButton::OnPressed() RelayoutRequest(); } +Dali::Accessibility::States ToggleButton::AccessibleImpl::CalculateStates() +{ + auto states = Button::AccessibleImpl::CalculateStates(); + auto button = Toolkit::ToggleButton::DownCast( self ); + if( button.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ) ) + states[Dali::Accessibility::State::CHECKED] = true; + return states; +} + +std::string ToggleButton::AccessibleImpl::GetDescriptionRaw() +{ + auto button = Toolkit::ToggleButton::DownCast( self ); + auto index = button.GetProperty( Toolkit::ToggleButton::Property::CURRENT_STATE_INDEX ); + auto tooltips = button.GetProperty( Toolkit::ToggleButton::Property::TOOLTIPS ); + + return tooltips[index].Get(); +} + +Property::Index ToggleButton::AccessibleImpl::GetDescriptionPropertyIndex() +{ + return Toolkit::ToggleButton::Property::TOOLTIPS; +} + +void ToggleButton::OnStateChange( State newState ) +{ + // TODO: replace it with OnPropertySet hook once Button::Property::SELECTED will be consistently used + if (Dali::Accessibility::IsUp() && (newState == SELECTED_STATE || newState == UNSELECTED_STATE)) + { + Dali::Accessibility::Accessible::Get(Self())->EmitStateChanged( + Dali::Accessibility::State::CHECKED, mCurrentToggleIndex ? 1 : 0, 0 + ); + + if(Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + Dali::Accessibility::Accessible::Get(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION); + } + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/buttons/toggle-button-impl.h b/dali-toolkit/internal/controls/buttons/toggle-button-impl.h index 138ee19..a3bb83a 100644 --- a/dali-toolkit/internal/controls/buttons/toggle-button-impl.h +++ b/dali-toolkit/internal/controls/buttons/toggle-button-impl.h @@ -163,6 +163,16 @@ private: std::vector mToggleDisabledSelectedVisuals; ///< Save all disabled selected visuals. std::vector mToggleTooltips; ///< Toggle tooltips. unsigned int mCurrentToggleIndex; ///< The index of state. +protected: + struct AccessibleImpl : public Button::AccessibleImpl + { + using Button::AccessibleImpl::AccessibleImpl; + + Dali::Accessibility::States CalculateStates() override; + std::string GetDescriptionRaw() override; + Property::Index GetDescriptionPropertyIndex() override; + }; + void OnStateChange( State newState ) override; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/control/control-data-impl.cpp b/dali-toolkit/internal/controls/control/control-data-impl.cpp index 368ab0a..df01b27 100755 --- a/dali-toolkit/internal/controls/control/control-data-impl.cpp +++ b/dali-toolkit/internal/controls/control/control-data-impl.cpp @@ -27,6 +27,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -39,6 +45,18 @@ #include #include #include +#include +#include + +namespace +{ + const std::string READING_INFO_TYPE_NAME = "name"; + const std::string READING_INFO_TYPE_ROLE = "role"; + const std::string READING_INFO_TYPE_DESCRIPTION = "description"; + const std::string READING_INFO_TYPE_STATE = "state"; + const std::string READING_INFO_TYPE_ATTRIBUTE_NAME = "reading_info_type"; + const std::string READING_INFO_TYPE_SEPARATOR = "|"; +} namespace Dali { @@ -171,21 +189,64 @@ void MoveVisual( RegisteredVisualContainer::Iterator sourceIter, RegisteredVisua * @param[in] attributes The attributes with which to perfrom this action. * @return true if action has been accepted by this control */ -const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated"; +const char* ACTION_ACCESSIBILITY_ACTIVATED = "accessibilityActivated"; +const char* ACTION_ACCESSIBILITY_READING_CANCELLED = "ReadingCancelled"; +const char* ACTION_ACCESSIBILITY_READING_PAUSED = "ReadingPaused"; +const char* ACTION_ACCESSIBILITY_READING_RESUMED = "ReadingResumed"; +const char* ACTION_ACCESSIBILITY_READING_SKIPPED = "ReadingSkipped"; +const char* ACTION_ACCESSIBILITY_READING_STOPPED = "ReadingStopped"; + static bool DoAction( BaseObject* object, const std::string& actionName, const Property::Map& attributes ) { - bool ret = false; + bool ret = true; + + Dali::BaseHandle handle( object ); + + Toolkit::Control control = Toolkit::Control::DownCast( handle ); - if( object && ( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) ) ) + DALI_ASSERT_ALWAYS( control ); + + if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_ACTIVATED ) || + actionName == "activate" ) { - Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); - if( control ) - { - // if cast succeeds there is an implementation so no need to check - ret = Internal::GetImplementation( control ).OnAccessibilityActivated(); - } + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityActivateSignal( control ).Empty() ) + DevelControl::AccessibilityActivateSignal( control ).Emit(); + else ret = Internal::GetImplementation( control ).OnAccessibilityActivated(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_SKIPPED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingSkippedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingSkippedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_PAUSED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingPausedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingPausedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_RESUMED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingResumedSignal( control ).Empty() ) + DevelControl::AccessibilityReadingResumedSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_CANCELLED ) ) + { + // if cast succeeds there is an implementation so no need to check + if( !DevelControl::AccessibilityReadingCancelledSignal( control ).Empty() ) + DevelControl::AccessibilityReadingCancelledSignal( control ).Emit(); + } + else if( 0 == strcmp( actionName.c_str(), ACTION_ACCESSIBILITY_READING_STOPPED ) ) + { + // if cast succeeds there is an implementation so no need to check + if(!DevelControl::AccessibilityReadingStoppedSignal( control ).Empty()) + DevelControl::AccessibilityReadingStoppedSignal( control ).Emit(); + } else + { + ret = false; } - return ret; } @@ -205,6 +266,9 @@ const char* SIGNAL_TAPPED = "tapped"; const char* SIGNAL_PANNED = "panned"; const char* SIGNAL_PINCHED = "pinched"; const char* SIGNAL_LONG_PRESSED = "longPressed"; +const char* SIGNAL_GET_NAME = "getName"; +const char* SIGNAL_GET_DESCRIPTION = "getDescription"; +const char* SIGNAL_DO_GESTURE = "doGesture"; static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) { Dali::BaseHandle handle( object ); @@ -248,6 +312,19 @@ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tra controlImpl.EnableGestureDetection( GestureType::LONG_PRESS ); controlImpl.GetLongPressGestureDetector().DetectedSignal().Connect( tracker, functor ); } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_GET_NAME ) ) + { + DevelControl::AccessibilityGetNameSignal( control ).Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_GET_DESCRIPTION ) ) + { + DevelControl::AccessibilityGetDescriptionSignal( control ).Connect( tracker, functor ); + } + else if( 0 == strcmp( signalName.c_str(), SIGNAL_DO_GESTURE ) ) + { + DevelControl::AccessibilityDoGestureSignal( control ).Connect( tracker, functor ); + } + } return connected; } @@ -271,8 +348,17 @@ SignalConnectorType registerSignal4( typeRegistration, SIGNAL_TAPPED, &DoConnect SignalConnectorType registerSignal5( typeRegistration, SIGNAL_PANNED, &DoConnectSignal ); SignalConnectorType registerSignal6( typeRegistration, SIGNAL_PINCHED, &DoConnectSignal ); SignalConnectorType registerSignal7( typeRegistration, SIGNAL_LONG_PRESSED, &DoConnectSignal ); - -TypeAction registerAction( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction ); +SignalConnectorType registerSignal8( typeRegistration, SIGNAL_GET_NAME, &DoConnectSignal ); +SignalConnectorType registerSignal9( typeRegistration, SIGNAL_GET_DESCRIPTION, &DoConnectSignal ); +SignalConnectorType registerSignal10( typeRegistration, SIGNAL_DO_GESTURE, &DoConnectSignal ); + +TypeAction registerAction1( typeRegistration, "activate", &DoAction ); +TypeAction registerAction2( typeRegistration, ACTION_ACCESSIBILITY_ACTIVATED, &DoAction ); +TypeAction registerAction3( typeRegistration, ACTION_ACCESSIBILITY_READING_SKIPPED, &DoAction ); +TypeAction registerAction4( typeRegistration, ACTION_ACCESSIBILITY_READING_CANCELLED, &DoAction ); +TypeAction registerAction5( typeRegistration, ACTION_ACCESSIBILITY_READING_STOPPED, &DoAction ); +TypeAction registerAction6( typeRegistration, ACTION_ACCESSIBILITY_READING_PAUSED, &DoAction ); +TypeAction registerAction7( typeRegistration, ACTION_ACCESSIBILITY_READING_RESUMED, &DoAction ); DALI_TYPE_REGISTRATION_END() @@ -311,7 +397,13 @@ const PropertyRegistration Control::Impl::PROPERTY_12( typeRegistration, "rightF const PropertyRegistration Control::Impl::PROPERTY_13( typeRegistration, "upFocusableActorId", Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_14( typeRegistration, "downFocusableActorId", Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); const PropertyRegistration Control::Impl::PROPERTY_15( typeRegistration, "shadow", Toolkit::DevelControl::Property::SHADOW, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); - +const PropertyRegistration Control::Impl::PROPERTY_16( typeRegistration, "accessibilityAttributes", Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES, Property::MAP, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_17( typeRegistration, "accessibilityName", Toolkit::DevelControl::Property::ACCESSIBILITY_NAME, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_18( typeRegistration, "accessibilityDescription", Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_19( typeRegistration, "accessibilityTranslationDomain", Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN, Property::STRING, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_20( typeRegistration, "accessibilityRole", Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE, Property::INTEGER, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_21( typeRegistration, "accessibilityHighlightable", Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); +const PropertyRegistration Control::Impl::PROPERTY_22( typeRegistration, "accessibilityAnimated", Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, Property::BOOLEAN, &Control::Impl::SetProperty, &Control::Impl::GetProperty ); Control::Impl::Impl( Control& controlImpl ) : mControlImpl( controlImpl ), @@ -331,6 +423,9 @@ Control::Impl::Impl( Control& controlImpl ) mKeyInputFocusLostSignal(), mResourceReadySignal(), mVisualEventSignal(), + mAccessibilityGetNameSignal(), + mAccessibilityGetDescriptionSignal(), + mAccessibilityDoGestureSignal(), mPinchGestureDetector(), mPanGestureDetector(), mTapGestureDetector(), @@ -344,10 +439,27 @@ Control::Impl::Impl( Control& controlImpl ) mIsEmittingResourceReadySignal(false), mNeedToEmitResourceReady(false) { + Dali::Accessibility::Accessible::RegisterControlAccessibilityGetter( + []( Dali::Actor actor ) -> Dali::Accessibility::Accessible* { + return Control::Impl::GetAccessibilityObject( actor ); + } ); + + accessibilityConstructor = []( Dali::Actor actor ) -> std::unique_ptr< Dali::Accessibility::Accessible > { + return std::unique_ptr< Dali::Accessibility::Accessible >( new AccessibleImpl( actor, + Dali::Accessibility::Role::UNKNOWN ) ); + }; + + size_t len = static_cast(Dali::Accessibility::RelationType::MAX_COUNT); + mAccessibilityRelations.reserve(len); + for (auto i = 0u; i < len; ++i) + { + mAccessibilityRelations.push_back({}); + } } Control::Impl::~Impl() { + AccessibilityDeregister(); // All gesture detectors will be destroyed so no need to disconnect. delete mStartingPinchScale; @@ -827,6 +939,20 @@ void Control::Impl::DoAction( Dali::Property::Index visualIndex, Dali::Property: } } +void Control::Impl::AppendAccessibilityAttribute( const std::string& key, + const std::string value ) +{ + Property::Value* val = mAccessibilityAttributes.Find( key ); + if( val ) + { + mAccessibilityAttributes[key] = Property::Value( value ); + } + else + { + mAccessibilityAttributes.Insert( key, value ); + } +} + void Control::Impl::SetProperty( BaseObject* object, Property::Index index, const Property::Value& value ) { Toolkit::Control control = Toolkit::Control::DownCast( BaseHandle( object ) ); @@ -900,6 +1026,76 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons } break; + case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME: + { + std::string name; + if( value.Get( name ) ) + { + controlImpl.mImpl->mAccessibilityName = name; + controlImpl.mImpl->mAccessibilityNameSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityNameSet = false; + } + } + break; + + case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: + { + std::string txt; + if( value.Get( txt ) ) + { + controlImpl.mImpl->mAccessibilityDescription = txt; + controlImpl.mImpl->mAccessibilityDescriptionSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityDescriptionSet = false; + } + } + break; + + case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: + { + std::string txt; + if( value.Get( txt ) ) + { + controlImpl.mImpl->mAccessibilityTranslationDomain = txt; + controlImpl.mImpl->mAccessibilityTranslationDomainSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityTranslationDomainSet = false; + } + } + break; + + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: + { + bool highlightable; + if( value.Get( highlightable ) ) + { + controlImpl.mImpl->mAccessibilityHighlightable = highlightable; + controlImpl.mImpl->mAccessibilityHighlightableSet = true; + } + else + { + controlImpl.mImpl->mAccessibilityHighlightableSet = false; + } + } + break; + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: + { + Dali::Accessibility::Role val; + if( value.Get( val ) ) + { + controlImpl.mImpl->mAccessibilityRole = val; + } + } + break; + case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: { int focusId; @@ -1009,6 +1205,17 @@ void Control::Impl::SetProperty( BaseObject* object, Property::Index index, cons break; } + case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES: + { + value.Get( controlImpl.mImpl->mAccessibilityAttributes ); + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED: + { + value.Get( controlImpl.mImpl->mAccessibilityAnimated ); + break; + } } } } @@ -1055,6 +1262,48 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index break; } + case Toolkit::DevelControl::Property::ACCESSIBILITY_NAME: + { + if (controlImpl.mImpl->mAccessibilityNameSet) + { + value = controlImpl.mImpl->mAccessibilityName; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_DESCRIPTION: + { + if (controlImpl.mImpl->mAccessibilityDescriptionSet) + { + value = controlImpl.mImpl->mAccessibilityDescription; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_TRANSLATION_DOMAIN: + { + if (controlImpl.mImpl->mAccessibilityTranslationDomainSet) + { + value = controlImpl.mImpl->mAccessibilityTranslationDomain; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE: + { + if (controlImpl.mImpl->mAccessibilityHighlightableSet) + { + value = controlImpl.mImpl->mAccessibilityHighlightable; + } + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: + { + value = Property::Value(controlImpl.mImpl->mAccessibilityRole); + break; + } + case Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID: { value = controlImpl.mImpl->mUpFocusableActorId; @@ -1121,12 +1370,105 @@ Property::Value Control::Impl::GetProperty( BaseObject* object, Property::Index value = map; break; } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES: + { + value = controlImpl.mImpl->mAccessibilityAttributes; + break; + } + + case Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED: + { + value = controlImpl.mImpl->mAccessibilityAnimated; + break; + } } } return value; } +void Control::Impl::RemoveAccessibilityAttribute( const std::string& key ) +{ + Property::Value* val = mAccessibilityAttributes.Find( key ); + if( val ) + mAccessibilityAttributes[key] = Property::Value(); +} + +void Control::Impl::ClearAccessibilityAttributes() +{ + mAccessibilityAttributes.Clear(); +} + +void Control::Impl::SetAccessibilityReadingInfoType( const Dali::Accessibility::ReadingInfoTypes types ) +{ + std::string value; + if ( types[ Dali::Accessibility::ReadingInfoType::NAME ] ) + { + value += READING_INFO_TYPE_NAME; + } + if ( types[ Dali::Accessibility::ReadingInfoType::ROLE ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_ROLE; + } + if ( types[ Dali::Accessibility::ReadingInfoType::DESCRIPTION ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_DESCRIPTION; + } + if ( types[ Dali::Accessibility::ReadingInfoType::STATE ] ) + { + if( !value.empty() ) + { + value += READING_INFO_TYPE_SEPARATOR; + } + value += READING_INFO_TYPE_STATE; + } + AppendAccessibilityAttribute( READING_INFO_TYPE_ATTRIBUTE_NAME, value ); +} + +Dali::Accessibility::ReadingInfoTypes Control::Impl::GetAccessibilityReadingInfoType() const +{ + std::string value; + auto place = mAccessibilityAttributes.Find( READING_INFO_TYPE_ATTRIBUTE_NAME ); + if( place ) + { + place->Get( value ); + } + + if ( value.empty() ) + { + return {}; + } + + Dali::Accessibility::ReadingInfoTypes types; + + if ( value.find( READING_INFO_TYPE_NAME ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::NAME ] = true; + } + if ( value.find( READING_INFO_TYPE_ROLE ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::ROLE ] = true; + } + if ( value.find( READING_INFO_TYPE_DESCRIPTION ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::DESCRIPTION ] = true; + } + if ( value.find( READING_INFO_TYPE_STATE ) != std::string::npos ) + { + types[ Dali::Accessibility::ReadingInfoType::STATE ] = true; + } + + return types; +} void Control::Impl::CopyInstancedProperties( RegisteredVisualContainer& visuals, Dictionary& instancedProperties ) { @@ -1512,6 +1854,455 @@ void Control::Impl::OnIdleCallback() mIdleCallback = nullptr; } +Dali::Accessibility::Accessible *Control::Impl::GetAccessibilityObject() +{ + if( !accessibilityObject ) + accessibilityObject = accessibilityConstructor( mControlImpl.Self() ); + return accessibilityObject.get(); +} + +Dali::Accessibility::Accessible *Control::Impl::GetAccessibilityObject(Dali::Actor actor) +{ + if( actor ) + { + auto q = Dali::Toolkit::Control::DownCast( actor ); + if( q ) + { + auto q2 = static_cast< Internal::Control* >( &q.GetImplementation() ); + return q2->mImpl->GetAccessibilityObject(); + } + } + return nullptr; +} + +Control::Impl::AccessibleImpl::AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal) + : self(self), modal(modal) +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + if( controlImpl.mAccessibilityRole == Dali::Accessibility::Role::UNKNOWN ) + controlImpl.mAccessibilityRole = role; + + self.PropertySetSignal().Connect(&controlImpl, [this, &controlImpl](Dali::Handle &handle, Dali::Property::Index index, Dali::Property::Value value) + { + if (this->self != Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + return; + } + + if (index == DevelControl::Property::ACCESSIBILITY_NAME + || (index == GetNamePropertyIndex() && !controlImpl.mAccessibilityNameSet)) + { + if (controlImpl.mAccessibilityGetNameSignal.Empty()) + { + Emit(Dali::Accessibility::ObjectPropertyChangeEvent::NAME); + } + } + + if (index == DevelControl::Property::ACCESSIBILITY_DESCRIPTION + || (index == GetDescriptionPropertyIndex() && !controlImpl.mAccessibilityDescriptionSet)) + { + if (controlImpl.mAccessibilityGetDescriptionSignal.Empty()) + { + Emit(Dali::Accessibility::ObjectPropertyChangeEvent::DESCRIPTION); + } + } + }); +} + +std::string Control::Impl::AccessibleImpl::GetName() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityGetNameSignal.Empty()) { + std::string ret; + controlImpl.mAccessibilityGetNameSignal.Emit(ret); + return ret; + } + + if (controlImpl.mAccessibilityNameSet) + return controlImpl.mAccessibilityName; + + if (auto raw = GetNameRaw(); !raw.empty()) + return raw; + + return self.GetProperty< std::string >( Actor::Property::NAME ); +} + +std::string Control::Impl::AccessibleImpl::GetNameRaw() +{ + return {}; +} + +std::string Control::Impl::AccessibleImpl::GetDescription() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityGetDescriptionSignal.Empty()) { + std::string ret; + controlImpl.mAccessibilityGetDescriptionSignal.Emit(ret); + return ret; + } + + if (controlImpl.mAccessibilityDescriptionSet) + return controlImpl.mAccessibilityDescription; + + return GetDescriptionRaw(); +} + +std::string Control::Impl::AccessibleImpl::GetDescriptionRaw() +{ + return ""; +} + +Dali::Accessibility::Accessible* Control::Impl::AccessibleImpl::GetParent() +{ + return Dali::Accessibility::Accessible::Get( self.GetParent() ); +} + +size_t Control::Impl::AccessibleImpl::GetChildCount() +{ + return self.GetChildCount(); +} + +Dali::Accessibility::Accessible* Control::Impl::AccessibleImpl::GetChildAtIndex( size_t index ) +{ + return Dali::Accessibility::Accessible::Get( self.GetChildAt( static_cast< unsigned int >( index ) ) ); +} + +size_t Control::Impl::AccessibleImpl::GetIndexInParent() +{ + auto s = self; + auto parent = s.GetParent(); + DALI_ASSERT_ALWAYS( parent && "can't call GetIndexInParent on object without parent" ); + auto count = parent.GetChildCount(); + for( auto i = 0u; i < count; ++i ) + { + auto c = parent.GetChildAt( i ); + if( c == s ) + return i; + } + DALI_ASSERT_ALWAYS( false && "object isn't child of it's parent" ); + return static_cast(-1); +} + +Dali::Accessibility::Role Control::Impl::AccessibleImpl::GetRole() +{ + return self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE ); +} + +Dali::Accessibility::States Control::Impl::AccessibleImpl::CalculateStates() +{ + Dali::Accessibility::States s; + s[Dali::Accessibility::State::FOCUSABLE] = self.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ); + s[Dali::Accessibility::State::FOCUSED] = Toolkit::KeyboardFocusManager::Get().GetCurrentFocusActor() == self; + if(self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).GetType() == Property::NONE ) + s[Dali::Accessibility::State::HIGHLIGHTABLE] = false; + else + s[Dali::Accessibility::State::HIGHLIGHTABLE] = self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE ).Get< bool >(); + s[Dali::Accessibility::State::HIGHLIGHTED] = GetCurrentlyHighlightedActor() == self; + s[Dali::Accessibility::State::ENABLED] = true; + s[Dali::Accessibility::State::SENSITIVE] = true; + s[Dali::Accessibility::State::ANIMATED] = self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED ).Get< bool >(); + s[Dali::Accessibility::State::VISIBLE] = true; + if( modal ) + { + s[Dali::Accessibility::State::MODAL] = true; + } + s[Dali::Accessibility::State::SHOWING] = !self.GetProperty( Dali::DevelActor::Property::CULLED ).Get< bool >() + && self.GetCurrentProperty< bool >( Actor::Property::VISIBLE ); + + s[Dali::Accessibility::State::DEFUNCT] = !self.GetProperty( Dali::DevelActor::Property::CONNECTED_TO_SCENE ).Get< bool >(); + return s; +} + +Dali::Accessibility::States Control::Impl::AccessibleImpl::GetStates() +{ + return CalculateStates(); +} + +Dali::Accessibility::Attributes Control::Impl::AccessibleImpl::GetAttributes() +{ + std::unordered_map< std::string, std::string > attribute_map; + auto q = Dali::Toolkit::Control::DownCast( self ); + auto w = + q.GetProperty( Dali::Toolkit::DevelControl::Property::ACCESSIBILITY_ATTRIBUTES ); + auto z = w.GetMap(); + + if( z ) + { + auto map_size = z->Count(); + + for( unsigned int i = 0; i < map_size; i++ ) + { + auto map_key = z->GetKeyAt( i ); + if( map_key.type == Property::Key::STRING ) + { + std::string map_value; + if( z->GetValue( i ).Get( map_value ) ) + { + attribute_map.emplace( std::move( map_key.stringKey ), + std::move( map_value ) ); + } + } + } + } + + return attribute_map; +} + +Dali::Accessibility::ComponentLayer Control::Impl::AccessibleImpl::GetLayer() +{ + return Dali::Accessibility::ComponentLayer::WINDOW; +} + +Dali::Rect<> Control::Impl::AccessibleImpl::GetExtents( Dali::Accessibility::CoordType ctype ) +{ + Vector2 screenPosition = + self.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION ) + .Get< Vector2 >(); + auto size = self.GetCurrentProperty< Vector3 >( Actor::Property::SIZE ) * self.GetCurrentProperty< Vector3 >( Actor::Property::WORLD_SCALE ); + bool positionUsesAnchorPoint = + self.GetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT ) + .Get< bool >(); + Vector3 anchorPointOffSet = + size * ( positionUsesAnchorPoint ? self.GetCurrentProperty< Vector3 >( Actor::Property::ANCHOR_POINT ) + : AnchorPoint::TOP_LEFT ); + Vector2 position = Vector2( screenPosition.x - anchorPointOffSet.x, + screenPosition.y - anchorPointOffSet.y ); + + return { position.x, position.y, size.x, size.y }; +} + +int16_t Control::Impl::AccessibleImpl::GetMdiZOrder() { return 0; } +double Control::Impl::AccessibleImpl::GetAlpha() { return 0; } + +bool Control::Impl::AccessibleImpl::GrabFocus() +{ + return Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( self ); +} + +const char* const FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "keyboard_focus.9.png"; + +static Dali::Actor CreateHighlightIndicatorActor() +{ + // Create the default if it hasn't been set and one that's shared by all the + // keyboard focusable actors const char* const FOCUS_BORDER_IMAGE_PATH = + // DALI_IMAGE_DIR "keyboard_focus.9.png"; + auto actor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH ); + actor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); + DevelControl::AppendAccessibilityAttribute( actor, "highlight", "" ); + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED, true); + actor.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false ); + + return actor; +} + +bool Control::Impl::AccessibleImpl::GrabHighlight() +{ + auto old = GetCurrentlyHighlightedActor(); + + if( !Dali::Accessibility::IsUp() ) + return false; + if( self == old ) + return true; + if( old ) + { + auto c = dynamic_cast< Dali::Accessibility::Component* >( GetAccessibilityObject( old ) ); + if( c ) + c->ClearHighlight(); + } + auto highlight = GetHighlightActor(); + if ( !highlight ) + { + highlight = CreateHighlightIndicatorActor(); + SetHighlightActor( highlight ); + } + highlight.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER ); + highlight.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER ); + highlight.SetProperty( Actor::Property::POSITION_Z, 1.0f ); + highlight.SetProperty( Actor::Property::POSITION, Vector2( 0.0f, 0.0f )); + + EnsureSelfVisible(); + self.Add( highlight ); + SetCurrentlyHighlightedActor( self ); + EmitHighlighted( true ); + + return true; +} + + + +bool Control::Impl::AccessibleImpl::ClearHighlight() +{ + if( !Dali::Accessibility::IsUp() ) + return false; + if( GetCurrentlyHighlightedActor() == self ) + { + self.Remove( GetHighlightActor() ); + SetCurrentlyHighlightedActor( {} ); + EmitHighlighted( false ); + return true; + } + return false; +} + +std::string Control::Impl::AccessibleImpl::GetActionName( size_t index ) +{ + if ( index >= GetActionCount() ) return ""; + Dali::TypeInfo type; + self.GetTypeInfo( type ); + DALI_ASSERT_ALWAYS( type && "no TypeInfo object" ); + return type.GetActionName( index ); +} +std::string Control::Impl::AccessibleImpl::GetLocalizedActionName( size_t index ) +{ + // TODO: add localization + return GetActionName( index ); +} +std::string Control::Impl::AccessibleImpl::GetActionDescription( size_t index ) +{ + return ""; +} +size_t Control::Impl::AccessibleImpl::GetActionCount() +{ + Dali::TypeInfo type; + self.GetTypeInfo( type ); + DALI_ASSERT_ALWAYS( type && "no TypeInfo object" ); + return type.GetActionCount(); +} +std::string Control::Impl::AccessibleImpl::GetActionKeyBinding( size_t index ) +{ + return ""; +} +bool Control::Impl::AccessibleImpl::DoAction( size_t index ) +{ + std::string actionName = GetActionName( index ); + return self.DoAction( actionName, {} ); +} +bool Control::Impl::AccessibleImpl::DoAction(const std::string& name) +{ + return self.DoAction( name, {} ); +} + +bool Control::Impl::AccessibleImpl::DoGesture(const Dali::Accessibility::GestureInfo &gestureInfo) +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + if (!controlImpl.mAccessibilityDoGestureSignal.Empty()) { + auto ret = std::make_pair(gestureInfo, false); + controlImpl.mAccessibilityDoGestureSignal.Emit(ret); + return ret.second; + } + + return false; +} + +std::vector Control::Impl::AccessibleImpl::GetRelationSet() +{ + auto control = Dali::Toolkit::Control::DownCast(self); + + Internal::Control& internalControl = Toolkit::Internal::GetImplementation( control ); + Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get( internalControl ); + + std::vector ret; + + auto &v = controlImpl.mAccessibilityRelations; + for (auto i = 0u; i < v.size(); ++i) + { + if ( v[i].empty() ) + continue; + + ret.emplace_back( Accessibility::Relation{ static_cast(i), v[i] } ); + } + + return ret; +} + +void Control::Impl::AccessibleImpl::EnsureChildVisible(Actor child) +{ +} + +void Control::Impl::AccessibleImpl::EnsureSelfVisible() +{ + auto parent = dynamic_cast(GetParent()); + if (parent) + { + parent->EnsureChildVisible(self); + } +} + +Property::Index Control::Impl::AccessibleImpl::GetNamePropertyIndex() +{ + return Actor::Property::NAME; +} + +Property::Index Control::Impl::AccessibleImpl::GetDescriptionPropertyIndex() +{ + return Property::INVALID_INDEX; +} + +void Control::Impl::PositionOrSizeChangedCallback( PropertyNotification &p ) +{ + auto self = Dali::Actor::DownCast(p.GetTarget()); + if (Dali::Accessibility::IsUp() && !self.GetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_ANIMATED ).Get< bool >()) + { + auto extents = DevelActor::CalculateScreenExtents( self ); + Dali::Accessibility::Accessible::Get( self )->EmitBoundsChanged( extents ); + } +} + +void Control::Impl::CulledChangedCallback( PropertyNotification &p) +{ + if (Dali::Accessibility::IsUp()) + { + auto self = Dali::Actor::DownCast(p.GetTarget()); + Dali::Accessibility::Accessible::Get(self)->EmitShowing( !self.GetProperty( DevelActor::Property::CULLED ).Get() ); + } +} + +void Control::Impl::AccessibilityRegister() +{ + if (!accessibilityNotificationSet) + { + accessibilityNotificationPosition = mControlImpl.Self().AddPropertyNotification( Actor::Property::POSITION, StepCondition( 0.01f ) ); + accessibilityNotificationPosition.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationPosition.NotifySignal().Connect( &Control::Impl::PositionOrSizeChangedCallback ); + + accessibilityNotificationSize = mControlImpl.Self().AddPropertyNotification( Actor::Property::SIZE, StepCondition( 0.01f ) ); + accessibilityNotificationSize.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationSize.NotifySignal().Connect( &Control::Impl::PositionOrSizeChangedCallback ); + + accessibilityNotificationCulled = mControlImpl.Self().AddPropertyNotification( DevelActor::Property::CULLED, LessThanCondition( 0.5f ) ); + accessibilityNotificationCulled.SetNotifyMode( PropertyNotification::NOTIFY_ON_CHANGED ); + accessibilityNotificationCulled.NotifySignal().Connect( &Control::Impl::CulledChangedCallback ); + + accessibilityNotificationSet = true; + } +} + +void Control::Impl::AccessibilityDeregister() +{ + if (accessibilityNotificationSet) + { + accessibilityNotificationPosition = {}; + accessibilityNotificationSize = {}; + accessibilityNotificationCulled = {}; + accessibilityNotificationSet = false; + } +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/control/control-data-impl.h b/dali-toolkit/internal/controls/control/control-data-impl.h index e042113..aefb484 100755 --- a/dali-toolkit/internal/controls/control/control-data-impl.h +++ b/dali-toolkit/internal/controls/control/control-data-impl.h @@ -20,7 +20,9 @@ // EXTERNAL INCLUDES #include +#include #include +#include #include // INTERNAL INCLUDES @@ -28,10 +30,14 @@ #include #include #include -#include -#include #include +#include +#include +#include #include +#include +#include +#include namespace Dali { @@ -332,6 +338,44 @@ public: bool FilterKeyEvent( const KeyEvent& event ); /** + * @brief Adds accessibility attribute + * @param[in] key Attribute name to set + * @param[in] value Attribute value to set + * + * Attribute is added if not existed previously or updated + * if existed. + */ + void AppendAccessibilityAttribute( const std::string& key, + const std::string value ); + + /** + * @brief Removes accessibility attribute + * @param[in] key Attribute name to remove + * + * Function does nothing if attribute doesn't exist. + */ + void RemoveAccessibilityAttribute( const std::string& key ); + + /** + * @brief Removes all accessibility attributes + */ + void ClearAccessibilityAttributes(); + + /** + * @brief Sets reading info type attributes + * @param[in] types info type attributes to set + * + * This function sets, which part of object will be read out + * by screen-reader. + */ + void SetAccessibilityReadingInfoType( const Dali::Accessibility::ReadingInfoTypes types ); + + /** + * @brief Gets currently active reading info type attributes + */ + Dali::Accessibility::ReadingInfoTypes GetAccessibilityReadingInfoType() const; + + /** * @copydoc DevelControl::VisualEventSignal() */ DevelControl::VisualEventSignalType& VisualEventSignal(); @@ -401,6 +445,7 @@ public: Control& mControlImpl; DevelControl::State mState; std::string mSubStateName; + Property::Map mAccessibilityAttributes; int mLeftFocusableActorId; ///< Actor ID of Left focusable control. int mRightFocusableActorId; ///< Actor ID of Right focusable control. @@ -418,6 +463,33 @@ public: Toolkit::Control::KeyInputFocusSignalType mKeyInputFocusLostSignal; Toolkit::Control::ResourceReadySignalType mResourceReadySignal; DevelControl::VisualEventSignalType mVisualEventSignal; + Toolkit::DevelControl::AccessibilityActivateSignalType mAccessibilityActivateSignal; + Toolkit::DevelControl::AccessibilityReadingSkippedSignalType mAccessibilityReadingSkippedSignal; + Toolkit::DevelControl::AccessibilityReadingPausedSignalType mAccessibilityReadingPausedSignal; + Toolkit::DevelControl::AccessibilityReadingResumedSignalType mAccessibilityReadingResumedSignal; + Toolkit::DevelControl::AccessibilityReadingCancelledSignalType mAccessibilityReadingCancelledSignal; + Toolkit::DevelControl::AccessibilityReadingStoppedSignalType mAccessibilityReadingStoppedSignal; + + Toolkit::DevelControl::AccessibilityGetNameSignalType mAccessibilityGetNameSignal; + Toolkit::DevelControl::AccessibilityGetDescriptionSignalType mAccessibilityGetDescriptionSignal; + Toolkit::DevelControl::AccessibilityDoGestureSignalType mAccessibilityDoGestureSignal; + + std::string mAccessibilityName; + bool mAccessibilityNameSet = false; + + std::string mAccessibilityDescription; + bool mAccessibilityDescriptionSet = false; + + std::string mAccessibilityTranslationDomain; + bool mAccessibilityTranslationDomainSet = false; + + bool mAccessibilityHighlightable = false; + bool mAccessibilityHighlightableSet = false; + + Dali::Accessibility::Role mAccessibilityRole = Dali::Accessibility::Role::UNKNOWN; + + std::vector> mAccessibilityRelations; + bool mAccessibilityAnimated = false; // Gesture Detection PinchGestureDetector mPinchGestureDetector; @@ -456,6 +528,77 @@ public: static const PropertyRegistration PROPERTY_13; static const PropertyRegistration PROPERTY_14; static const PropertyRegistration PROPERTY_15; + static const PropertyRegistration PROPERTY_16; + static const PropertyRegistration PROPERTY_17; + static const PropertyRegistration PROPERTY_18; + static const PropertyRegistration PROPERTY_19; + static const PropertyRegistration PROPERTY_20; + static const PropertyRegistration PROPERTY_21; + static const PropertyRegistration PROPERTY_22; + + /** + * The method acquires Accessible handle from Actor object + * @param actor Actor object + * @return handle to Accessible object + */ + static Dali::Accessibility::Accessible *GetAccessibilityObject(Dali::Actor actor); + Dali::Accessibility::Accessible *GetAccessibilityObject(); + + void AccessibilityRegister(); + void AccessibilityDeregister(); + + struct AccessibleImpl : public virtual Dali::Accessibility::Accessible, + public virtual Dali::Accessibility::Component, + public virtual Dali::Accessibility::Collection, + public virtual Dali::Accessibility::Action + { + Dali::Actor self; + bool modal = false, root = false; + + AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal = false); + + std::string GetName() override; + virtual std::string GetNameRaw(); + std::string GetDescription() override; + virtual std::string GetDescriptionRaw(); + Dali::Accessibility::Accessible* GetParent() override; + size_t GetChildCount() override; + Dali::Accessibility::Accessible* GetChildAtIndex( size_t index ) override; + size_t GetIndexInParent() override; + Dali::Accessibility::Role GetRole() override; + Dali::Accessibility::States GetStates() override; + Dali::Accessibility::Attributes GetAttributes() override; + Dali::Rect<> GetExtents( Dali::Accessibility::CoordType ctype ) override; + Dali::Accessibility::ComponentLayer GetLayer() override; + int16_t GetMdiZOrder() override; + bool GrabFocus() override; + double GetAlpha() override; + bool GrabHighlight() override; + bool ClearHighlight() override; + + std::string GetActionName( size_t index ) override; + std::string GetLocalizedActionName( size_t index ) override; + std::string GetActionDescription( size_t index ) override; + size_t GetActionCount() override; + std::string GetActionKeyBinding(size_t index) override; + bool DoAction(size_t index) override; + bool DoAction(const std::string& name) override; + bool DoGesture(const Dali::Accessibility::GestureInfo &gestureInfo) override; + std::vector GetRelationSet() override; + + virtual Dali::Accessibility::States CalculateStates(); + virtual void EnsureChildVisible(Actor child); + virtual void EnsureSelfVisible(); + virtual Property::Index GetNamePropertyIndex(); + virtual Property::Index GetDescriptionPropertyIndex(); + }; + + std::function< std::unique_ptr< Dali::Accessibility::Accessible >( Actor ) > accessibilityConstructor; + std::unique_ptr< Dali::Accessibility::Accessible > accessibilityObject; + Dali::PropertyNotification accessibilityNotificationPosition, accessibilityNotificationSize, accessibilityNotificationCulled; + bool accessibilityNotificationSet = false; + static void PositionOrSizeChangedCallback( PropertyNotification& ); + static void CulledChangedCallback( PropertyNotification& ); }; diff --git a/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp b/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp index 752f268..f23d985 100644 --- a/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp +++ b/dali-toolkit/internal/controls/effects-view/effects-view-impl.cpp @@ -36,6 +36,7 @@ #include #include #include +#include namespace Dali { @@ -267,6 +268,11 @@ void EffectsView::OnInitialize() CustomActor self = Self(); mChildrenRoot.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER ); self.Add( mChildrenRoot ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } void EffectsView::OnSizeSet(const Vector3& targetSize) diff --git a/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp b/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp index 0fc7588..5dc8719 100755 --- a/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp +++ b/dali-toolkit/internal/controls/flex-container/flex-container-impl.cpp @@ -28,6 +28,9 @@ #include #include +// INTERNAL INCLUDES +#include + using namespace Dali; namespace @@ -844,6 +847,11 @@ void FlexContainer::OnInitialize() // Make self as keyboard focusable and focus group self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE, true ); SetAsKeyboardFocusGroup( true ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } } // namespace Internal diff --git a/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp b/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp index 453fb96..93fb35b 100644 --- a/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp +++ b/dali-toolkit/internal/controls/gaussian-blur-view/gaussian-blur-view-impl.cpp @@ -36,6 +36,7 @@ // INTERNAL INCLUDES #include #include +#include // TODO: // pixel format / size - set from JSON @@ -320,6 +321,11 @@ void GaussianBlurView::OnInitialize() mInternalRoot.Add( mHorizBlurActor ); mInternalRoot.Add( mVertBlurActor ); mInternalRoot.Add( mRenderDownsampledCamera ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } diff --git a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp old mode 100755 new mode 100644 index 36702a8..cb2dc99 --- a/dali-toolkit/internal/controls/image-view/image-view-impl.cpp +++ b/dali-toolkit/internal/controls/image-view/image-view-impl.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace Dali { @@ -95,6 +96,15 @@ void ImageView::OnInitialize() // ImageView can relayout in the OnImageReady, alternative to a signal would be to have a upcall from the Control to ImageView Dali::Toolkit::Control handle( GetOwner() ); handle.ResourceReadySignal().Connect( this, &ImageView::OnResourceReady ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::IMAGE ) ); + } ); + + //Enable highightability + Self().SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + } void ImageView::SetImage( const Property::Map& map ) diff --git a/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp b/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp index 478c14b..0be5d46 100644 --- a/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp +++ b/dali-toolkit/internal/controls/magnifier/magnifier-impl.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace Dali { @@ -219,6 +220,11 @@ void Magnifier::Initialize() constraint.AddSource( Source( self, Actor::Property::SIZE ) ); constraint.AddSource( Source( self, Actor::Property::WORLD_SCALE ) ); constraint.Apply(); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } Magnifier::~Magnifier() diff --git a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp index a4f927a..5b49909 100644 --- a/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp +++ b/dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp @@ -30,6 +30,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { @@ -461,6 +462,10 @@ void Model3dView::OnInitialize() Shader shader = Shader::New( SIMPLE_VERTEX_SHADER, SIMPLE_FRAGMENT_SHADER ); mRenderer = Renderer::New( mesh, shader ); + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::IMAGE ) ); + } ); } void Model3dView::LoadGeometry() diff --git a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp index 58913da..4573b4c 100644 --- a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp +++ b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.cpp @@ -22,6 +22,7 @@ #include // INTERNAL INCLUDES +#include namespace Dali { @@ -71,6 +72,14 @@ Toolkit::NavigationView NavigationView::New() return navigationView; } +void NavigationView::OnInitialize() +{ + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); +} + void NavigationView::OnSceneConnection( int depth ) { Self().SetProperty( Actor::Property::SENSITIVE,true); diff --git a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h index d766ebe..820499a 100644 --- a/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h +++ b/dali-toolkit/internal/controls/navigation-view/navigation-view-impl.h @@ -78,6 +78,11 @@ public: private: // override functions from Control /** + * @copydoc Constrol::OnInitialize + */ + virtual void OnInitialize() override; + + /** * @copydoc Control::OnSceneConnection( int depth ) */ void OnSceneConnection( int depth ) override; diff --git a/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp b/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp index e258b69..df3bf6f 100644 --- a/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp +++ b/dali-toolkit/internal/controls/page-turn-view/page-turn-view-impl.cpp @@ -32,6 +32,7 @@ #include #include #include +#include using namespace Dali; @@ -414,6 +415,11 @@ void PageTurnView::OnInitialize() // enable the pan gesture which is attached to the control EnableGestureDetection(GestureType::Value(GestureType::PAN)); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::PAGE_TAB_LIST ) ); + } ); } Shader PageTurnView::CreateShader( const Property::Map& shaderMap ) diff --git a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp index 1092c13..0f1a585 100644 --- a/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp +++ b/dali-toolkit/internal/controls/popup/confirmation-popup-impl.cpp @@ -23,6 +23,9 @@ #include #include +// INTERNAL INCLUDES +#include + namespace Dali { diff --git a/dali-toolkit/internal/controls/popup/popup-impl.cpp b/dali-toolkit/internal/controls/popup/popup-impl.cpp index b95e648..092569c 100644 --- a/dali-toolkit/internal/controls/popup/popup-impl.cpp +++ b/dali-toolkit/internal/controls/popup/popup-impl.cpp @@ -39,10 +39,11 @@ #include #include #include -#include #include #include #include +#include +#include using namespace Dali; @@ -338,6 +339,13 @@ void Popup::OnInitialize() SetAsKeyboardFocusGroup( true ); SetupTouch(); + + DevelControl::AppendAccessibilityAttribute(self, "sub-role", "Alert"); + + DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) + { + return std::unique_ptr(new AccessibleImpl(actor, Dali::Accessibility::Role::DIALOG, true)); + }); } Popup::~Popup() @@ -563,8 +571,11 @@ void Popup::DisplayStateChangeComplete() bool Popup::OnAutoHideTimeReached() { - // Display timer has expired, auto hide the popup exactly as if the user had clicked outside. - SetDisplayState( Toolkit::Popup::HIDDEN ); + if (!Dali::Accessibility::IsUp() || true) // TODO: remove 'true' in sync with EFL (UX change) + { + // Display timer has expired, auto hide the popup exactly as if the user had clicked outside. + SetDisplayState( Toolkit::Popup::HIDDEN ); + } if( mAutoHideTimer ) { @@ -713,6 +724,18 @@ void Popup::SetDisplayState( Toolkit::Popup::DisplayState displayState ) return; } + auto *accessible = Dali::Accessibility::Accessible::Get(Self()); + if (display) + { + Dali::Accessibility::Bridge::GetCurrentBridge()->AddPopup(accessible); + accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 1, 0); + } + else + { + accessible->EmitStateChanged(Dali::Accessibility::State::SHOWING, 0, 0); + Dali::Accessibility::Bridge::GetCurrentBridge()->RemovePopup(accessible); + } + // Convert the bool state to the actual display state to use. mDisplayState = display ? Toolkit::Popup::SHOWING : Toolkit::Popup::HIDING; @@ -1978,6 +2001,39 @@ void Popup::SetupTouch() } } +std::string Popup::AccessibleImpl::GetNameRaw() +{ + auto popup = Toolkit::Popup::DownCast( self ); + std::string title; + Actor popupTitle = popup.GetTitle(); + if (popupTitle) + { + std::string titleText = popupTitle.GetProperty(Toolkit::TextLabel::Property::TEXT); + title = titleText; + } + else + { + Actor popupContent = popup.GetContent(); + if (popupContent) + { + std::string contentText = popupContent.GetProperty(Toolkit::TextLabel::Property::TEXT); + title = contentText; + } + } + return title; +} + +Dali::Accessibility::States Popup::AccessibleImpl::CalculateStates() +{ + auto states = Control::Impl::AccessibleImpl::CalculateStates(); + auto popup = Toolkit::Popup::DownCast(self); + auto displayState = popup.GetProperty(Toolkit::Popup::Property::DISPLAY_STATE); + + states[Dali::Accessibility::State::SHOWING] = (displayState == "SHOWN" || displayState == "SHOWING"); + + return states; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/popup/popup-impl.h b/dali-toolkit/internal/controls/popup/popup-impl.h index a7f7120..e9dffef 100644 --- a/dali-toolkit/internal/controls/popup/popup-impl.h +++ b/dali-toolkit/internal/controls/popup/popup-impl.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Dali { @@ -244,6 +245,13 @@ public: static Property::Value GetProperty( BaseObject* object, Property::Index propertyIndex ); protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + std::string GetNameRaw() override; + Dali::Accessibility::States CalculateStates() override; + }; /** * Construct a new Popup. diff --git a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp old mode 100755 new mode 100644 index 0a4a7e5..7251b48 --- a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp +++ b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.cpp @@ -166,6 +166,12 @@ ProgressBar::~ProgressBar() void ProgressBar::OnInitialize() { + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::PROGRESS_BAR ) ); + } ); + //Enable highightability + Self().SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); } void ProgressBar::OnRelayout( const Vector2& size, RelayoutContainer& container ) @@ -266,6 +272,10 @@ void ProgressBar::SetProgressValue( float value ) Toolkit::ProgressBar self = Toolkit::ProgressBar::DownCast( Self() ); mValueChangedSignal.Emit( self, mProgressValue, mSecondaryProgressValue ); + if (Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE); + } RelayoutRequest(); } } @@ -670,6 +680,29 @@ void ProgressBar::OnSceneConnection( int depth ) } } +double ProgressBar::AccessibleImpl::GetMinimum() { return DEFAULT_LOWER_BOUND; } + +double ProgressBar::AccessibleImpl::GetCurrent() +{ + auto p = Toolkit::ProgressBar::DownCast( self ); + return p.GetProperty( Toolkit::ProgressBar::Property::PROGRESS_VALUE ) + .Get< float >(); +} + +double ProgressBar::AccessibleImpl::GetMaximum() { return DEFAULT_UPPER_BOUND; } + +bool ProgressBar::AccessibleImpl::SetCurrent( double current ) +{ + if( current < GetMinimum() || current > GetMaximum() ) + return false; + auto p = Toolkit::ProgressBar::DownCast( self ); + p.SetProperty( Toolkit::ProgressBar::Property::PROGRESS_VALUE, + static_cast< float >( current ) ); + return true; +} + +double ProgressBar::AccessibleImpl::GetMinimumIncrement() { return 0.0; } + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h old mode 100755 new mode 100644 index bdc5da9..8d33e02 --- a/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h +++ b/dali-toolkit/internal/controls/progress-bar/progress-bar-impl.h @@ -24,6 +24,7 @@ #include #include #include +#include namespace Dali { @@ -269,6 +270,18 @@ private: Property::Map mTrackVisualMap; ///< To backup visual properties when switching determinate/indeterminate. Property::Map mProgressVisualMap; ///< To backup visual properties when switching determinate/indeterminate. Property::Map mSecondaryProgressVisualMap; ///< To backup visual properties when switching determinate/indeterminate. + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Value + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + double GetMinimum() override; + double GetCurrent() override; + double GetMaximum() override; + bool SetCurrent( double ) override; + double GetMinimumIncrement() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp index 54dc431..0627759 100644 --- a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp +++ b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.cpp @@ -215,6 +215,11 @@ void ScrollBar::OnInitialize() { CreateDefaultIndicatorActor(); Self().SetProperty( Actor::Property::DRAW_MODE,DrawMode::OVERLAY_2D); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::SCROLL_BAR ) ); + } ); } void ScrollBar::SetScrollPropertySource( Handle handle, Property::Index propertyScrollPosition, Property::Index propertyMinScrollPosition, Property::Index propertyMaxScrollPosition, Property::Index propertyScrollContentSize ) @@ -363,6 +368,10 @@ void ScrollBar::OnScrollPositionIntervalReached(PropertyNotification& source) if(scrollableHandle) { mScrollPositionIntervalReachedSignal.Emit( scrollableHandle.GetCurrentProperty< float >( mPropertyScrollPosition ) ); + if (Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE); + } } } @@ -858,6 +867,50 @@ Toolkit::ScrollBar ScrollBar::New(Toolkit::ScrollBar::Direction direction) return handle; } +double ScrollBar::AccessibleImpl::GetMinimum() +{ + auto p = Toolkit::ScrollBar::DownCast( self ); + Handle scrollableHandle = GetImpl( p ).mScrollableObject.GetHandle(); + return scrollableHandle ? scrollableHandle.GetCurrentProperty< float >( GetImpl( p ).mPropertyMinScrollPosition ) : 0.0f; +} + +double ScrollBar::AccessibleImpl::GetCurrent() +{ + auto p = Toolkit::ScrollBar::DownCast( self ); + Handle scrollableHandle = GetImpl( p ).mScrollableObject.GetHandle(); + return scrollableHandle ? scrollableHandle.GetCurrentProperty< float >( GetImpl( p ).mPropertyScrollPosition ) : 0.0f; +} + +double ScrollBar::AccessibleImpl::GetMaximum() +{ + auto p = Toolkit::ScrollBar::DownCast( self ); + Handle scrollableHandle = GetImpl( p ).mScrollableObject.GetHandle(); + return scrollableHandle ? scrollableHandle.GetCurrentProperty< float >( GetImpl( p ).mPropertyMaxScrollPosition ) : 1.0f; +} + +bool ScrollBar::AccessibleImpl::SetCurrent( double current ) +{ + if( current < GetMinimum() || current > GetMaximum() ) + return false; + + auto value_before = GetCurrent(); + + auto p = Toolkit::ScrollBar::DownCast( self ); + Handle scrollableHandle = GetImpl( p ).mScrollableObject.GetHandle(); + if( !scrollableHandle ) + return false; + scrollableHandle.SetProperty( GetImpl( p ).mPropertyScrollPosition, static_cast< float >( current ) ); + + auto value_after = GetCurrent(); + + if( ( current != value_before ) && ( value_before == value_after ) ) + return false; + + return true; +} + +double ScrollBar::AccessibleImpl::GetMinimumIncrement() { return 1.0; } + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h index de93aca..9bfe909 100644 --- a/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h +++ b/dali-toolkit/internal/controls/scroll-bar/scroll-bar-impl.h @@ -29,6 +29,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -285,9 +286,9 @@ private: WeakHandle mScrollableObject; ///< Object to be scrolled - Property::Index mPropertyScrollPosition; ///< Index of scroll position property owned by the object to be scrolled - Property::Index mPropertyMinScrollPosition; ///< Index of minimum scroll position property owned by the object to be scrolled - Property::Index mPropertyMaxScrollPosition; ///< Index of maximum scroll position property owned by the object to be scrolled + Property::Index mPropertyScrollPosition = 0; ///< Index of scroll position property owned by the object to be scrolled + Property::Index mPropertyMinScrollPosition = 0; ///< Index of minimum scroll position property owned by the object to be scrolled + Property::Index mPropertyMaxScrollPosition = 1; ///< Index of maximum scroll position property owned by the object to be scrolled Property::Index mPropertyScrollContentSize; ///< Index of scroll content size property owned by the object to be scrolled float mIndicatorShowDuration; ///< The duration of scroll indicator show animation @@ -319,6 +320,18 @@ private: bool mIsPanning : 1; ///< Whether the scroll bar is being panned. bool mIndicatorFirstShow : 1; ///< True if the indicator has never been shown + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Value + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + double GetMinimum() override; + double GetCurrent() override; + double GetMaximum() override; + bool SetCurrent( double ) override; + double GetMinimumIncrement() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp index 12bd0c3..b8b8baf 100644 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.cpp @@ -22,7 +22,7 @@ #include // for strcmp #include #include - +#include #include #include #include @@ -362,6 +362,8 @@ ItemView::ItemView(ItemFactory& factory) void ItemView::OnInitialize() { + Scrollable::OnInitialize(); + Actor self = Self(); Vector2 stageSize = Stage::GetCurrent().GetSize(); @@ -377,6 +379,11 @@ void ItemView::OnInitialize() // Connect wheel event self.WheelEventSignal().Connect( this, &ItemView::OnWheelEvent ); + + DevelControl::SetAccessibilityConstructor(self, [](Dali::Actor actor) + { + return std::unique_ptr(new AccessibleImpl(actor, Dali::Accessibility::Role::SCROLL_PANE)); + }); } ItemView::~ItemView() @@ -1353,6 +1360,13 @@ void ItemView::OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor) } } +void ItemView::AccessibleImpl::EnsureChildVisible(Actor child) +{ + EnsureSelfVisible(); + auto itemView = Dali::Toolkit::ItemView::DownCast(self); + Toolkit::GetImpl(itemView).OnKeyboardFocusChangeCommitted(child); +} + Animation ItemView::DoAnchoring() { Animation anchoringAnimation; diff --git a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h index 07cb9d5..0af85fc 100755 --- a/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h +++ b/dali-toolkit/internal/controls/scrollable/item-view/item-view-impl.h @@ -442,6 +442,12 @@ private: // From Control void OnKeyboardFocusChangeCommitted(Actor commitedFocusableActor) override; protected: + struct AccessibleImpl : public Scrollable::AccessibleImpl + { + using Scrollable::AccessibleImpl::AccessibleImpl; + + void EnsureChildVisible(Actor child) override; + }; /** * Construct a new ItemView. diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp index ffc7570..1a5c766 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.cpp @@ -33,13 +33,6 @@ namespace Internal // ScrollBase /////////////////////////////////////////////////////////////////////////////////////////////////// -ScrollBase::ScrollBase() -: Scrollable(), - mParent(NULL), - mDelay(0.0f) -{ -} - ScrollBase::ScrollBase( ControlBehaviour behaviourFlags ) : Scrollable( behaviourFlags ), mParent(NULL), diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h index aa34f20..9780e78 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-base-impl.h @@ -187,9 +187,9 @@ protected: protected: /** - * Construct a new ScrollBase. + * Removed default costructor. */ - ScrollBase(); + ScrollBase() = delete; /** * @brief Construct a new ScrollBase. diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp index 01c5731..c0943dc 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.cpp @@ -20,6 +20,7 @@ // EXTERNAL INCLUDES #include // for strcmp +#include #include #include #include @@ -706,6 +707,11 @@ void ScrollView::OnInitialize() // Connect wheel event self.WheelEventSignal().Connect( this, &ScrollView::OnWheelEvent ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::SCROLL_PANE ) ); + } ); } void ScrollView::OnSceneConnection( int depth ) @@ -1828,6 +1834,12 @@ Toolkit::ScrollView::SnapStartedSignalType& ScrollView::SnapStartedSignal() return mSnapStartedSignal; } +void ScrollView::AccessibleImpl::EnsureChildVisible(Actor child) +{ + auto scrollView = Dali::Toolkit::ScrollView::DownCast(self); + scrollView.ScrollTo(child); +} + void ScrollView::FindAndUnbindActor(Actor child) { UnbindActor(child); diff --git a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h index 2bda8c8..8724033 100644 --- a/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h +++ b/dali-toolkit/internal/controls/scrollable/scroll-view/scroll-view-impl.h @@ -801,6 +801,12 @@ private: void SetInternalConstraints(); protected: + struct AccessibleImpl : public Scrollable::AccessibleImpl + { + using Scrollable::AccessibleImpl::AccessibleImpl; + + void EnsureChildVisible(Actor child) override; + }; /** * Construct a new ScrollView. diff --git a/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp b/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp index 6cd2e67..7077239 100644 --- a/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp +++ b/dali-toolkit/internal/controls/scrollable/scrollable-impl.cpp @@ -22,6 +22,7 @@ // INTERNAL INCLUDES #include +#include using namespace Dali; @@ -78,21 +79,6 @@ const Vector2 OVERSHOOT_DEFAULT_SIZE( 720.0f, 42.0f ); // Scrollable /////////////////////////////////////////////////////////////////////////////////////////////////// -// Scrollable controls are not layout containers so they dont need size negotiation.. -// we dont want size negotiation while scrolling if we can avoid it -Scrollable::Scrollable() -: Control( ControlBehaviour( DISABLE_SIZE_NEGOTIATION ) ), - mOvershootEffectColor( DEFAULT_OVERSHOOT_COLOUR ), - mOvershootAnimationSpeed ( DEFAULT_OVERSHOOT_ANIMATION_SPEED ), - mOvershootSize( OVERSHOOT_DEFAULT_SIZE ), - mScrollToAlphaFunction( AlphaFunction::EASE_OUT ), - mScrollStartedSignal(), - mScrollUpdatedSignal(), - mScrollCompletedSignal(), - mOvershootEnabled(true) -{ -} - Scrollable::Scrollable( ControlBehaviour behaviourFlags ) : Control( ControlBehaviour( behaviourFlags ) ), mOvershootEffectColor( DEFAULT_OVERSHOOT_COLOUR ), @@ -110,6 +96,19 @@ Scrollable::~Scrollable() { } +bool Scrollable::AccessibleImpl::IsScrollable() +{ + return true; +} + +void Scrollable::OnInitialize() +{ + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::SCROLL_PANE ) ); + } ); +} + bool Scrollable::IsOvershootEnabled() const { return mOvershootEnabled; diff --git a/dali-toolkit/internal/controls/scrollable/scrollable-impl.h b/dali-toolkit/internal/controls/scrollable/scrollable-impl.h index 9ffdc8e..9967fde 100644 --- a/dali-toolkit/internal/controls/scrollable/scrollable-impl.h +++ b/dali-toolkit/internal/controls/scrollable/scrollable-impl.h @@ -24,6 +24,7 @@ // INTERNAL INCLUDES #include #include +#include namespace Dali { @@ -118,6 +119,19 @@ public: */ virtual void SetOvershootSize( const Vector2& size ) = 0; +protected: // From Control + struct AccessibleImpl : public Control::Impl::AccessibleImpl + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + bool IsScrollable() override; + }; + + /** + * @copydoc Control::OnInitialize + */ + virtual void OnInitialize() override; + private: /** @@ -176,9 +190,9 @@ public: //Signals protected: /** - * Construct a new Scrollable. + * Removed default constructor. */ - Scrollable(); + Scrollable() = delete; /** * @brief Construct a new Scrollable. diff --git a/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp b/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp index 217101b..37f7f53 100644 --- a/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp +++ b/dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp @@ -34,6 +34,7 @@ #include #include #include +#include // TODO: // pixel format / size - set from JSON @@ -289,6 +290,11 @@ void ShadowView::OnInitialize() Constraint blurStrengthConstraint = Constraint::New( mBlurFilter.GetHandleForAnimateBlurStrength(), mBlurFilter.GetBlurStrengthPropertyIndex(), EqualToConstraint() ); blurStrengthConstraint.AddSource( Source( self, mBlurStrengthPropertyIndex) ); blurStrengthConstraint.Apply(); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } void ShadowView::OnChildAdd( Actor& child ) diff --git a/dali-toolkit/internal/controls/slider/slider-impl.cpp b/dali-toolkit/internal/controls/slider/slider-impl.cpp index 742311a..e2dc5e3 100644 --- a/dali-toolkit/internal/controls/slider/slider-impl.cpp +++ b/dali-toolkit/internal/controls/slider/slider-impl.cpp @@ -203,8 +203,16 @@ void Slider::OnInitialize() // Size the Slider actor to a default self.SetProperty( Actor::Property::SIZE, Vector2( DEFAULT_HIT_REGION.x, DEFAULT_HIT_REGION.y ) ); + // Set the Slider to be highlightable in Screen Reader mode + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + // Connect to the touch signal self.TouchedSignal().Connect( this, &Slider::OnTouch ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::SLIDER ) ); + } ); } void Slider::OnRelayout( const Vector2& size, RelayoutContainer& container ) @@ -606,6 +614,7 @@ Toolkit::TextLabel Slider::CreatePopupText() textLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); textLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" ); textLabel.SetProperty( Actor::Property::PADDING, Padding( POPUP_TEXT_PADDING, POPUP_TEXT_PADDING, 0.0f, 0.0f ) ); + textLabel.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false ); return textLabel; } @@ -689,6 +698,7 @@ void Slider::CreateHandleValueDisplay() mHandleValueTextLabel.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER ); mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "CENTER" ); mHandleValueTextLabel.SetProperty( Toolkit::TextLabel::Property::VERTICAL_ALIGNMENT, "CENTER" ); + mHandleValueTextLabel.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, false ); mHandle.Add( mHandleValueTextLabel ); } } @@ -837,19 +847,9 @@ float Slider::MarkFilter( float value ) { const float MARK_TOLERANCE = GetMarkTolerance(); - float mark; - for( MarkList::SizeType i = 0; i < mMarks.Count(); ++i) - { - const Property::Value& propertyValue = mMarks[i]; - propertyValue.Get( mark ); - mark = MapValuePercentage( mark ); - - // If close to a mark, return the mark - if( fabsf( mark - value ) < MARK_TOLERANCE ) - { - return mark; - } - } + float mark = SnapToMark(value); + if (fabsf(mark - value) < MARK_TOLERANCE) + return mark; return value; } @@ -950,6 +950,10 @@ void Slider::SetValue( float value ) { mValue = value; DisplayValue( mValue, true ); + if (Self() == Dali::Accessibility::Accessible::GetCurrentlyHighlightedActor()) + { + Control::Impl::GetAccessibilityObject(Self())->Emit(Dali::Accessibility::ObjectPropertyChangeEvent::VALUE); + } } float Slider::GetValue() const @@ -1409,6 +1413,83 @@ Property::Value Slider::GetProperty( BaseObject* object, Property::Index propert return value; } +double Slider::AccessibleImpl::GetMinimum() +{ + auto p = Toolkit::Slider::DownCast( self ); + return p.GetProperty( Toolkit::Slider::Property::LOWER_BOUND ).Get< float >(); +} + +double Slider::AccessibleImpl::GetCurrent() +{ + auto p = Toolkit::Slider::DownCast( self ); + return p.GetProperty( Toolkit::Slider::Property::VALUE ).Get< float >(); +} + +double Slider::AccessibleImpl::GetMaximum() +{ + auto p = Toolkit::Slider::DownCast( self ); + return p.GetProperty( Toolkit::Slider::Property::UPPER_BOUND ).Get< float >(); +} + +bool Slider::AccessibleImpl::SetCurrent( double current ) +{ + if (current < GetMinimum() || current > GetMaximum()) + return false; + + auto p = Toolkit::Slider::DownCast( self ); + auto &impl = Toolkit::GetImpl(p); + + const float prev = p.GetProperty(Toolkit::Slider::Property::VALUE); + float next = static_cast(current); + + if (fabsf(next - prev) < Math::MACHINE_EPSILON_0) + { + // do nothing + } + else if (p.GetProperty(Toolkit::Slider::Property::SNAP_TO_MARKS)) + { + auto marks = p.GetProperty(Toolkit::Slider::Property::MARKS); + + int prevIdx; + if (impl.MarkReached(impl.MapValuePercentage(prev), prevIdx)) + { + int nextIdx = prevIdx; + nextIdx += (next > prev) ? 1 : -1; + + if (nextIdx < 0 || nextIdx >= static_cast(marks.Count())) + return false; + + next = marks[nextIdx].Get(); + } + else + { + next = impl.MapBounds(impl.SnapToMark(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound()); + } + } + else + { + next = impl.MapBounds(impl.MarkFilter(impl.MapValuePercentage(next)), impl.GetLowerBound(), impl.GetUpperBound()); + } + + impl.SetValue(next); + impl.DisplayPopup(next); + + return true; +} + +double Slider::AccessibleImpl::GetMinimumIncrement() +{ + auto p = Toolkit::Slider::DownCast( self ); + + bool hasMarks = !p.GetProperty(Toolkit::Slider::Property::MARKS).Empty(); + float tolerance = p.GetProperty(Toolkit::Slider::Property::MARK_TOLERANCE); + + if (!hasMarks || fabsf(tolerance) < 0.01) + return 0.0; // let screen-reader choose the increment + + return Math::MACHINE_EPSILON_10000 + tolerance * (GetMaximum() - GetMinimum()); +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/slider/slider-impl.h b/dali-toolkit/internal/controls/slider/slider-impl.h old mode 100755 new mode 100644 index d79c636..c078271 --- a/dali-toolkit/internal/controls/slider/slider-impl.h +++ b/dali-toolkit/internal/controls/slider/slider-impl.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace Dali { @@ -744,17 +745,29 @@ private: Vector2 mTrackRegion; ///< Size of track region Vector2 mHandleSize; ///< Size of the handle - float mLowerBound; ///< Lower bound on value - float mUpperBound; ///< Upper bound on value - float mValue; ///< Current value of slider + float mLowerBound = 0.0f; ///< Lower bound on value + float mUpperBound = 1.0f; ///< Upper bound on value + float mValue = 0.0f; ///< Current value of slider - float mMarkTolerance; ///< Tolerance in percentage of slider width for which to snap to marks + float mMarkTolerance = 0.05f; ///< Tolerance in percentage of slider width for which to snap to marks int mValuePrecision; ///< The precision to use for outputting the value bool mShowPopup : 1, ///< Show the popup or not mShowValue : 1, ///< Whether to display the value number or not on the handle mSnapToMarks : 1; ///< Turn on or off snapping to marks + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Value + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + double GetMinimum() override; + double GetCurrent() override; + double GetMaximum() override; + bool SetCurrent( double ) override; + double GetMinimumIncrement() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp b/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp index 6ed846f..769a7fc 100644 --- a/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp +++ b/dali-toolkit/internal/controls/super-blur-view/super-blur-view-impl.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace //Unnamed namespace { @@ -163,6 +164,11 @@ void SuperBlurView::OnInitialize() Actor self( Self() ); mBlurStrengthPropertyIndex = self.RegisterProperty( "blurStrength", 0.f ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::FILLER ) ); + } ); } void SuperBlurView::SetTexture( Texture texture ) diff --git a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp index 92cdd01..4f27bba 100755 --- a/dali-toolkit/internal/controls/table-view/table-view-impl.cpp +++ b/dali-toolkit/internal/controls/table-view/table-view-impl.cpp @@ -28,6 +28,9 @@ #include #include +// INTERNAL INCLUDES +#include + using namespace Dali; namespace @@ -1119,6 +1122,11 @@ void TableView::OnInitialize() Actor self = Self(); self.SetProperty( Actor::Property::KEYBOARD_FOCUSABLE,true); SetAsKeyboardFocusGroup(true); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TABLE ) ); + } ); } void TableView::ResizeContainers( unsigned int rows, unsigned int columns ) diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp index 75f6d6f..dc82c36 100644 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1158,6 +1159,11 @@ DevelTextEditor::MaxLengthReachedSignalType& TextEditor::MaxLengthReachedSignal( return mMaxLengthReachedSignal; } +Text::ControllerPtr TextEditor::getController() +{ + return mController; +} + bool TextEditor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor ) { Dali::BaseHandle handle( object ); @@ -1268,6 +1274,9 @@ void TextEditor::OnInitialize() self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT ); self.OnSceneSignal().Connect( this, &TextEditor::OnSceneConnect ); + //Enable highightability + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + DevelControl::SetInputMethodContext( *this, mInputMethodContext ); // Creates an extra control to be used as stencil buffer. @@ -1285,6 +1294,11 @@ void TextEditor::OnInitialize() mStencil.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS ); self.Add( mStencil ); + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::ENTRY ) ); + } ); } void TextEditor::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) @@ -1516,6 +1530,12 @@ void TextEditor::OnKeyInputFocusLost() EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last. } +bool TextEditor::OnAccessibilityActivated() +{ + SetKeyInputFocus(); + return true; +} + void TextEditor::OnTap( const TapGesture& gesture ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnTap %p\n", mController.Get() ); @@ -1574,6 +1594,30 @@ void TextEditor::RequestTextRelayout() RelayoutRequest(); } +void TextEditor::TextInserted( unsigned int position, unsigned int length, const std::string &content ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextInserted( position, length, content ); + } +} + +void TextEditor::TextDeleted( unsigned int position, unsigned int length, const std::string &content ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextDeleted( position, length, content ); + } +} + +void TextEditor::CaretMoved( unsigned int position ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextCaretMoved( position ); + } +} + void TextEditor::TextChanged() { Dali::Toolkit::TextEditor handle( GetOwner() ); @@ -1914,6 +1958,220 @@ TextEditor::~TextEditor() } } +std::string TextEditor::AccessibleImpl::GetName() +{ + auto slf = Toolkit::TextEditor::DownCast( self ); + return slf.GetProperty( Toolkit::TextEditor::Property::TEXT ) + .Get< std::string >(); +} + +std::string TextEditor::AccessibleImpl::GetText( size_t startOffset, + size_t endOffset ) +{ + if( endOffset <= startOffset ) + return {}; + + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >(); + + if( startOffset > txt.size() || endOffset > txt.size() ) + return {}; + + return txt.substr( startOffset, endOffset - startOffset ); +} + +size_t TextEditor::AccessibleImpl::GetCharacterCount() +{ + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >(); + + return txt.size(); +} + +size_t TextEditor::AccessibleImpl::GetCaretOffset() +{ + auto slf = Toolkit::TextEditor::DownCast( self ); + return Dali::Toolkit::GetImpl( slf ).getController()->GetCursorPosition(); +} + +bool TextEditor::AccessibleImpl::SetCaretOffset(size_t offset) +{ + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >(); + if (offset > txt.size()) + return false; + + auto& slfImpl = Dali::Toolkit::GetImpl( slf ); + slfImpl.getController()->ResetCursorPosition( offset ); + slfImpl.RequestTextRelayout(); + return true; +} + +Dali::Accessibility::Range TextEditor::AccessibleImpl::GetTextAtOffset( + size_t offset, Dali::Accessibility::TextBoundary boundary ) +{ + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get< std::string >(); + auto txt_size = txt.size(); + + auto range = Dali::Accessibility::Range{}; + + switch(boundary) + { + case Dali::Accessibility::TextBoundary::CHARACTER: + { + if (offset < txt_size) + { + range.content = txt[offset]; + range.startOffset = offset; + range.endOffset = offset + 1; + } + } + break; + case Dali::Accessibility::TextBoundary::WORD: + case Dali::Accessibility::TextBoundary::LINE: + { + auto txt_c_string = txt.c_str(); + auto breaks = std::vector< char >( txt_size, 0 ); + if(boundary == Dali::Accessibility::TextBoundary::WORD) + Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + else + Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + auto index = 0u; + auto counter = 0u; + while( index < txt_size && counter <= offset ) + { + auto start = index; + if(breaks[index]) + { + while(breaks[index]) + index++; + counter++; + } + else + { + if (boundary == Dali::Accessibility::TextBoundary::WORD) + index++; + if (boundary == Dali::Accessibility::TextBoundary::LINE) + counter++; + } + if ((counter > 0) && ((counter - 1) == offset)) + { + range.content = txt.substr(start, index - start + 1); + range.startOffset = start; + range.endOffset = index + 1; + } + if (boundary == Dali::Accessibility::TextBoundary::LINE) + index++; + } + } + break; + case Dali::Accessibility::TextBoundary::SENTENCE: + { + /* not supported by efl */ + } + break; + case Dali::Accessibility::TextBoundary::PARAGRAPH: + { + /* Paragraph is not supported by libunibreak library */ + } + break; + default: + break; + } + + return range; +} + +Dali::Accessibility::Range +TextEditor::AccessibleImpl::GetSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return {}; + + auto slf = Toolkit::TextEditor::DownCast( self ); + auto ctrl = Dali::Toolkit::GetImpl( slf ).getController(); + std::string ret; + ctrl->RetrieveSelection( ret ); + auto r = ctrl->GetSelectionIndexes(); + + return { static_cast(r.first), static_cast(r.second), ret }; +} + +bool TextEditor::AccessibleImpl::RemoveSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextEditor::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( 0, 0 ); + return true; +} + +bool TextEditor::AccessibleImpl::SetSelection( size_t selectionNum, + size_t startOffset, + size_t endOffset ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextEditor::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( startOffset, + endOffset ); + return true; +} + +bool TextEditor::AccessibleImpl::CopyText( size_t startPosition, + size_t endPosition ) +{ + if( endPosition <= startPosition ) + return false; + + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get(); + Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) ); + + return true; +} + +bool TextEditor::AccessibleImpl::CutText( size_t startPosition, + size_t endPosition ) +{ + if( endPosition <= startPosition ) + return false; + + auto slf = Toolkit::TextEditor::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextEditor::Property::TEXT ).Get(); + Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) ); + + slf.SetProperty( Toolkit::TextEditor::Property::TEXT, + txt.substr( 0, startPosition ) + txt.substr( endPosition - startPosition, txt.size())); + + return true; +} + +Dali::Accessibility::States TextEditor::AccessibleImpl::CalculateStates() +{ + using namespace Dali::Accessibility; + + auto states = Control::Impl::AccessibleImpl::CalculateStates(); + states[State::EDITABLE] = true; + states[State::FOCUSABLE] = true; + + Toolkit::Control focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl(); + if (self == focusControl) + { + states[State::FOCUSED] = true; + } + + return states; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h index 0cb7204..c2385a2 100755 --- a/dali-toolkit/internal/controls/text-controls/text-editor-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-editor-impl.h @@ -21,6 +21,7 @@ // EXTERNAL INCLUDES #include #include +#include #include // INTERNAL INCLUDES @@ -35,6 +36,7 @@ #include #include #include +#include namespace Dali { @@ -150,6 +152,11 @@ private: // From Control void OnKeyInputFocusLost() override; /** + * @copydoc Control::OnAccessibilityActivated() + */ + bool OnAccessibilityActivated() override; + + /** * @copydoc Control::OnTap() */ void OnTap( const TapGesture& tap ) override; @@ -186,6 +193,21 @@ private: // From Control /** * @copydoc Text::EditableControlInterface::TextChanged() */ + void TextInserted( unsigned int position, unsigned int length, const std::string &content ) override; + + /** + * @copydoc Text::EditableControlInterface::TextDeleted() + */ + void TextDeleted( unsigned int position, unsigned int length, const std::string &content ) override; + + /** + * @copydoc Text::EditableControlInterface::CaretMoved() + */ + void CaretMoved( unsigned int position ) override; + + /** + * @copydoc Text::EditableControlInterface::TextChanged() + */ void TextChanged() override; /** @@ -258,6 +280,7 @@ public: * @copydoc Text::EditableControlInterface::SetEditable() */ void SetEditable( bool editable ) override; + Text::ControllerPtr getController(); private: // Implementation @@ -375,6 +398,29 @@ private: // Data bool mScrollAnimationEnabled:1; bool mScrollBarEnabled:1; bool mScrollStarted:1; + + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Text, + public virtual Dali::Accessibility::EditableText + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + std::string GetName() override; + std::string GetText( size_t startOffset, size_t endOffset ) override; + size_t GetCharacterCount() override; + size_t GetCaretOffset() override; + bool SetCaretOffset(size_t offset) override; + Dali::Accessibility::Range + GetTextAtOffset( size_t offset, + Dali::Accessibility::TextBoundary boundary ) override; + Dali::Accessibility::Range GetSelection( size_t selectionNum ) override; + bool RemoveSelection( size_t selectionNum ) override; + bool SetSelection( size_t selectionNum, size_t startOffset, + size_t endOffset ) override; + bool CopyText( size_t startPosition, size_t endPosition ) override; + bool CutText( size_t startPosition, size_t endPosition ) override; + Dali::Accessibility::States CalculateStates() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index a85a342..312a54e 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -1235,12 +1235,20 @@ void TextField::OnInitialize() self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::HEIGHT ); self.OnSceneSignal().Connect( this, &TextField::OnSceneConnect ); + //Enable highightability + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + DevelControl::SetInputMethodContext( *this, mInputMethodContext ); if( Dali::Toolkit::TextField::EXCEED_POLICY_CLIP == mExceedPolicy ) { EnableClipping(); } + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::ENTRY ) ); + } ); } void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) @@ -1372,6 +1380,8 @@ void TextField::OnRelayout( const Vector2& size, RelayoutContainer& container ) } } +Text::ControllerPtr TextField::getController() { return mController; } + void TextField::RenderText( Text::Controller::UpdateTextType updateTextType ) { Actor renderableActor; @@ -1526,6 +1536,12 @@ void TextField::OnKeyInputFocusLost() EmitKeyInputFocusSignal( false ); // Calls back into the Control hence done last. } +bool TextField::OnAccessibilityActivated() +{ + SetKeyInputFocus(); + return true; +} + void TextField::OnTap( const TapGesture& gesture ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnTap %p\n", mController.Get() ); @@ -1603,6 +1619,30 @@ void TextField::SetEditable( bool editable ) } } +void TextField::TextInserted( unsigned int position, unsigned int length, const std::string &content ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextInserted( position, length, content ); + } +} + +void TextField::TextDeleted( unsigned int position, unsigned int length, const std::string &content ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextDeleted( position, length, content ); + } +} + +void TextField::CaretMoved( unsigned int position ) +{ + if( Accessibility::IsUp() ) + { + Control::Impl::GetAccessibilityObject( Self() )->EmitTextCaretMoved( position ); + } +} + void TextField::TextChanged() { Dali::Toolkit::TextField handle( GetOwner() ); @@ -1798,6 +1838,220 @@ TextField::~TextField() } } +std::string TextField::AccessibleImpl::GetName() +{ + auto slf = Toolkit::TextField::DownCast( self ); + return slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get< std::string >(); +} + +std::string TextField::AccessibleImpl::GetText( size_t startOffset, + size_t endOffset ) +{ + if( endOffset <= startOffset ) + return {}; + + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get< std::string >(); + + if( startOffset > txt.size() || endOffset > txt.size() ) + return {}; + + return txt.substr( startOffset, endOffset - startOffset ); +} + +size_t TextField::AccessibleImpl::GetCharacterCount() +{ + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get< std::string >(); + + return txt.size(); +} + +size_t TextField::AccessibleImpl::GetCaretOffset() +{ + auto slf = Toolkit::TextField::DownCast( self ); + return Dali::Toolkit::GetImpl( slf ).getController()->GetCursorPosition(); +} + +bool TextField::AccessibleImpl::SetCaretOffset(size_t offset) +{ + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get< std::string >(); + if (offset > txt.size()) + return false; + + auto& slfImpl = Dali::Toolkit::GetImpl( slf ); + slfImpl.getController()->ResetCursorPosition( offset ); + slfImpl.RequestTextRelayout(); + return true; +} + +Dali::Accessibility::Range TextField::AccessibleImpl::GetTextAtOffset( + size_t offset, Dali::Accessibility::TextBoundary boundary ) +{ + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get< std::string >(); + auto txt_size = txt.size(); + + auto range = Dali::Accessibility::Range{}; + + switch(boundary) + { + case Dali::Accessibility::TextBoundary::CHARACTER: + { + if (offset < txt_size) + { + range.content = txt[offset]; + range.startOffset = offset; + range.endOffset = offset + 1; + } + } + break; + case Dali::Accessibility::TextBoundary::WORD: + case Dali::Accessibility::TextBoundary::LINE: + { + auto txt_c_string = txt.c_str(); + auto breaks = std::vector< char >( txt_size, 0 ); + if(boundary == Dali::Accessibility::TextBoundary::WORD) + Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + else + Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + auto index = 0u; + auto counter = 0u; + while( index < txt_size && counter <= offset ) + { + auto start = index; + if(breaks[index]) + { + while(breaks[index]) + index++; + counter++; + } + else + { + if (boundary == Dali::Accessibility::TextBoundary::WORD) + index++; + if (boundary == Dali::Accessibility::TextBoundary::LINE) + counter++; + } + if ((counter > 0) && ((counter - 1) == offset)) + { + range.content = txt.substr(start, index - start + 1); + range.startOffset = start; + range.endOffset = index + 1; + } + if (boundary == Dali::Accessibility::TextBoundary::LINE) + index++; + } + } + break; + case Dali::Accessibility::TextBoundary::SENTENCE: + { + /* not supported by efl */ + } + break; + case Dali::Accessibility::TextBoundary::PARAGRAPH: + { + /* Paragraph is not supported by libunibreak library */ + } + break; + default: + break; + } + + return range; +} + +Dali::Accessibility::Range +TextField::AccessibleImpl::GetSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return {}; + + auto slf = Toolkit::TextField::DownCast( self ); + auto ctrl = Dali::Toolkit::GetImpl( slf ).getController(); + std::string ret; + ctrl->RetrieveSelection( ret ); + auto r = ctrl->GetSelectionIndexes(); + + return { static_cast(r.first), static_cast(r.second), ret }; +} + +bool TextField::AccessibleImpl::RemoveSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextField::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( 0, 0 ); + return true; +} + +bool TextField::AccessibleImpl::SetSelection( size_t selectionNum, + size_t startOffset, + size_t endOffset ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextField::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( startOffset, + endOffset ); + return true; +} + +bool TextField::AccessibleImpl::CopyText( size_t startPosition, + size_t endPosition ) +{ + if( endPosition <= startPosition ) + return false; + + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get(); + Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) ); + + return true; +} + +bool TextField::AccessibleImpl::CutText( size_t startPosition, + size_t endPosition ) +{ + if( endPosition <= startPosition ) + return false; + + auto slf = Toolkit::TextField::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextField::Property::TEXT ).Get(); + Dali::Toolkit::GetImpl( slf ).getController()->CopyStringToClipboard( txt.substr(startPosition, endPosition - startPosition) ); + + slf.SetProperty( Toolkit::TextField::Property::TEXT, + txt.substr( 0, startPosition ) + txt.substr( endPosition - startPosition, txt.size())); + + return true; +} + +Dali::Accessibility::States TextField::AccessibleImpl::CalculateStates() +{ + using namespace Dali::Accessibility; + + auto states = Control::Impl::AccessibleImpl::CalculateStates(); + + states[State::EDITABLE] = true; + states[State::FOCUSABLE] = true; + + Toolkit::Control focusControl = Toolkit::KeyInputFocusManager::Get().GetCurrentFocusControl(); + if (self == focusControl) + { + states[State::FOCUSED] = true; + } + + return states; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.h b/dali-toolkit/internal/controls/text-controls/text-field-impl.h index 329d7b5..157e832 100755 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace Dali { @@ -103,6 +104,8 @@ public: */ Toolkit::TextField::InputStyleChangedSignalType& InputStyleChangedSignal(); + Text::ControllerPtr getController(); + private: // From Control /** @@ -141,6 +144,11 @@ private: // From Control void OnKeyInputFocusLost() override; /** + * @copydoc Control::OnAccessibilityActivated() + */ + bool OnAccessibilityActivated() override; + + /** * @copydoc Control::OnTap() */ void OnTap( const TapGesture& tap ) override; @@ -177,6 +185,21 @@ private: // From Control /** * @copydoc Text::EditableControlInterface::TextChanged() */ + void TextInserted( unsigned int position, unsigned int length, const std::string &content ) override; + + /** + * @copydoc Text::EditableControlInterface::TextDeleted() + */ + void TextDeleted( unsigned int position, unsigned int length, const std::string &content ) override; + + /** + * @copydoc Text::EditableControlInterface::CaretMoved() + */ + void CaretMoved( unsigned int position ) override; + + /** + * @copydoc Text::EditableControlInterface::TextChanged() + */ void TextChanged() override; /** @@ -329,6 +352,30 @@ private: // Data int mRenderingBackend; int mExceedPolicy; bool mHasBeenStaged:1; + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Text, + public virtual Dali::Accessibility::EditableText + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + std::string GetName() override; + std::string GetText( size_t startOffset, size_t endOffset ) override; + size_t GetCharacterCount() override; + size_t GetCaretOffset() override; + bool SetCaretOffset(size_t offset) override; + Dali::Accessibility::Range + GetTextAtOffset( size_t offset, + Dali::Accessibility::TextBoundary boundary ) override; + Dali::Accessibility::Range GetSelection( size_t selectionNum ) override; + bool RemoveSelection( size_t selectionNum ) override; + bool SetSelection( size_t selectionNum, size_t startOffset, + size_t endOffset ) override; + bool CopyText( size_t startPosition, size_t endPosition ) override; + bool CutText( size_t startPosition, size_t endPosition ) override; + Dali::Accessibility::States CalculateStates() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp index d1c1b1a..3ecb376 100755 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.cpp @@ -479,6 +479,8 @@ void TextLabel::SetProperty( BaseObject* object, Property::Index index, const Pr } } +Text::ControllerPtr TextLabel::getController() { return mController; } + Property::Value TextLabel::GetProperty( BaseObject* object, Property::Index index ) { Property::Value value; @@ -719,6 +721,9 @@ void TextLabel::OnInitialize() self.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH ); self.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT ); + // Enable highlightability + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); + // Enable the text ellipsis. mController->SetTextElideEnabled( true ); // If false then text larger than control will overflow @@ -729,6 +734,11 @@ void TextLabel::OnInitialize() Layout::Engine& engine = mController->GetLayoutEngine(); engine.SetCursorWidth( 0u ); // Do not layout space for the cursor. + + DevelControl::SetAccessibilityConstructor( self, []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new AccessibleImpl( actor, Dali::Accessibility::Role::LABEL ) ); + } ); } void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change ) @@ -973,6 +983,169 @@ TextLabel::~TextLabel() { } +std::string TextLabel::AccessibleImpl::GetNameRaw() +{ + auto slf = Toolkit::TextLabel::DownCast( self ); + return slf.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get< std::string >(); +} + +Property::Index TextLabel::AccessibleImpl::GetNamePropertyIndex() +{ + return Toolkit::TextLabel::Property::TEXT; +} + +std::string TextLabel::AccessibleImpl::GetText( size_t startOffset, + size_t endOffset ) +{ + if( endOffset <= startOffset ) + return {}; + + auto slf = Toolkit::TextLabel::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get< std::string >(); + + if( startOffset > txt.size() || endOffset > txt.size() ) + return {}; + + return txt.substr( startOffset, endOffset - startOffset ); +} + +size_t TextLabel::AccessibleImpl::GetCharacterCount() +{ + auto slf = Toolkit::TextLabel::DownCast( self ); + auto txt = + slf.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get< std::string >(); + + return txt.size(); +} + +size_t TextLabel::AccessibleImpl::GetCaretOffset() +{ + return {}; +} + +bool TextLabel::AccessibleImpl::SetCaretOffset(size_t offset) +{ + return {}; +} + +Dali::Accessibility::Range TextLabel::AccessibleImpl::GetTextAtOffset( + size_t offset, Dali::Accessibility::TextBoundary boundary ) +{ + auto slf = Toolkit::TextLabel::DownCast( self ); + auto txt = slf.GetProperty( Toolkit::TextLabel::Property::TEXT ).Get< std::string >(); + auto txt_size = txt.size(); + + auto range = Dali::Accessibility::Range{}; + + switch(boundary) + { + case Dali::Accessibility::TextBoundary::CHARACTER: + { + if (offset < txt_size) + { + range.content = txt[offset]; + range.startOffset = offset; + range.endOffset = offset + 1; + } + } + break; + case Dali::Accessibility::TextBoundary::WORD: + case Dali::Accessibility::TextBoundary::LINE: + { + auto txt_c_string = txt.c_str(); + auto breaks = std::vector< char >( txt_size, 0 ); + if(boundary == Dali::Accessibility::TextBoundary::WORD) + Accessibility::Accessible::FindWordSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + else + Accessibility::Accessible::FindLineSeparationsUtf8((const utf8_t *) txt_c_string, txt_size, "", breaks.data()); + auto index = 0u; + auto counter = 0u; + while( index < txt_size && counter <= offset ) + { + auto start = index; + if(breaks[index]) + { + while(breaks[index]) + index++; + counter++; + } + else + { + if (boundary == Dali::Accessibility::TextBoundary::WORD) + index++; + if (boundary == Dali::Accessibility::TextBoundary::LINE) + counter++; + } + if ((counter > 0) && ((counter - 1) == offset)) + { + range.content = txt.substr(start, index - start + 1); + range.startOffset = start; + range.endOffset = index + 1; + } + if (boundary == Dali::Accessibility::TextBoundary::LINE) + index++; + } + } + break; + case Dali::Accessibility::TextBoundary::SENTENCE: + { + /* not supported by efl */ + } + break; + case Dali::Accessibility::TextBoundary::PARAGRAPH: + { + /* Paragraph is not supported by libunibreak library */ + } + break; + default: + break; + } + + return range; +} + +Dali::Accessibility::Range +TextLabel::AccessibleImpl::GetSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return {}; + + auto slf = Toolkit::TextLabel::DownCast( self ); + auto ctrl = Dali::Toolkit::GetImpl( slf ).getController(); + std::string ret; + ctrl->RetrieveSelection( ret ); + auto r = ctrl->GetSelectionIndexes(); + + return { static_cast(r.first), static_cast(r.second), ret }; +} + +bool TextLabel::AccessibleImpl::RemoveSelection( size_t selectionNum ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextLabel::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( 0, 0 ); + return true; +} + +bool TextLabel::AccessibleImpl::SetSelection( size_t selectionNum, + size_t startOffset, + size_t endOffset ) +{ + // Since DALi supports only one selection indexes higher than 0 are ignored + if( selectionNum > 0 ) + return false; + + auto slf = Toolkit::TextLabel::DownCast( self ); + Dali::Toolkit::GetImpl( slf ).getController()->SetSelection( startOffset, + endOffset ); + return true; +} + } // namespace Internal } // namespace Toolkit diff --git a/dali-toolkit/internal/controls/text-controls/text-label-impl.h b/dali-toolkit/internal/controls/text-controls/text-label-impl.h index a863c9c..926128e 100644 --- a/dali-toolkit/internal/controls/text-controls/text-label-impl.h +++ b/dali-toolkit/internal/controls/text-controls/text-label-impl.h @@ -30,6 +30,7 @@ #include #include #include +#include namespace Dali @@ -73,6 +74,8 @@ public: */ static Property::Value GetProperty( BaseObject* object, Property::Index index ); + Text::ControllerPtr getController(); + private: // From Control /** @@ -164,6 +167,27 @@ private: // Data int mRenderingBackend; bool mTextUpdateNeeded:1; + +protected: + struct AccessibleImpl : public Control::Impl::AccessibleImpl, + public virtual Dali::Accessibility::Text + { + using Control::Impl::AccessibleImpl::AccessibleImpl; + + std::string GetText( size_t startOffset, size_t endOffset ) override; + size_t GetCharacterCount() override; + size_t GetCaretOffset() override; + bool SetCaretOffset(size_t offset) override; + Dali::Accessibility::Range + GetTextAtOffset( size_t offset, + Dali::Accessibility::TextBoundary boundary ) override; + Dali::Accessibility::Range GetSelection( size_t selectionNum ) override; + bool RemoveSelection( size_t selectionNum ) override; + bool SetSelection( size_t selectionNum, size_t startOffset, + size_t endOffset ) override; + std::string GetNameRaw() override; + Property::Index GetNamePropertyIndex() override; + }; }; } // namespace Internal diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp index 6631898..bf7b618 100644 --- a/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-selection-popup-impl.cpp @@ -42,6 +42,7 @@ #include #include #include +#include namespace Dali { @@ -386,6 +387,14 @@ void TextSelectionPopup::OnInitialize() Actor self = Self(); self.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::ALL_DIMENSIONS ); self.SetProperty( Actor::Property::COLOR_ALPHA, 0.0f ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::DIALOG, true ) ); + } ); + + //Enable highightability + self.SetProperty( Toolkit::DevelControl::Property::ACCESSIBILITY_HIGHLIGHTABLE, true ); } void TextSelectionPopup::HideAnimationFinished( Animation& animation ) diff --git a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp index 8cdd32a..792dead 100644 --- a/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-selection-toolbar-impl.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace Dali { @@ -166,6 +167,11 @@ Property::Value TextSelectionToolbar::GetProperty( BaseObject* object, Property: void TextSelectionToolbar::OnInitialize() { SetUp(); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TOOL_BAR )); + } ); } void TextSelectionToolbar::OnRelayout( const Vector2& size, RelayoutContainer& container ) diff --git a/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp b/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp index 33431c9..1519920 100644 --- a/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp +++ b/dali-toolkit/internal/controls/tool-bar/tool-bar-impl.cpp @@ -25,6 +25,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { @@ -313,6 +314,11 @@ void ToolBar::OnInitialize() mLayout.AddChild( rightSpace, Toolkit::TableView::CellPosition( 0, 1 ) ); mLayout.SetRelativeWidth( 0, mLeftRelativeSpace ); mLayout.SetRelativeWidth( 1, mRightRelativeSpace ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::TOOL_BAR )); + } ); } void ToolBar::OnChildAdd(Actor& child) diff --git a/dali-toolkit/internal/controls/tooltip/tooltip.cpp b/dali-toolkit/internal/controls/tooltip/tooltip.cpp index e7f8b9f..3a2ccc0 100644 --- a/dali-toolkit/internal/controls/tooltip/tooltip.cpp +++ b/dali-toolkit/internal/controls/tooltip/tooltip.cpp @@ -277,7 +277,7 @@ void Tooltip::SetContent( Toolkit::Control& control, const Property::Value& valu if( value.Get( text ) ) { mContentTextVisual[ Toolkit::TextVisual::Property::TEXT ] = text; - mContentTextVisual[ Toolkit::Visual::Property::TYPE ] = Visual::TEXT; + mContentTextVisual[ Toolkit::Visual::Property::TYPE ] = Toolkit::Visual::TEXT; mContentArray.Clear(); connectSignals = true; } diff --git a/dali-toolkit/internal/controls/video-view/video-view-impl.cpp b/dali-toolkit/internal/controls/video-view/video-view-impl.cpp index d7d812c..6956cb2 100755 --- a/dali-toolkit/internal/controls/video-view/video-view-impl.cpp +++ b/dali-toolkit/internal/controls/video-view/video-view-impl.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace Dali { @@ -158,6 +159,11 @@ Toolkit::VideoView VideoView::New( VideoSyncMode syncMode ) void VideoView::OnInitialize() { mVideoPlayer.FinishedSignal().Connect( this, &VideoView::EmitSignalFinish ); + + DevelControl::SetAccessibilityConstructor( Self(), []( Dali::Actor actor ) { + return std::unique_ptr< Dali::Accessibility::Accessible >( + new Control::Impl::AccessibleImpl( actor, Dali::Accessibility::Role::VIDEO )); + } ); } void VideoView::SetUrl( const std::string& url ) diff --git a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp index 5092cfe..04c15c4 100644 --- a/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp +++ b/dali-toolkit/internal/focus-manager/keyboard-focus-manager-impl.cpp @@ -21,7 +21,6 @@ // EXTERNAL INCLUDES #include // for strcmp #include -#include #include #include #include @@ -39,10 +38,10 @@ #include #include #include -#include #include #include #include +#include namespace Dali { @@ -746,11 +745,6 @@ Actor KeyboardFocusManager::GetFocusIndicatorActor() void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) { - AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get(); - bool isAccessibilityEnabled = accessibilityAdaptor.IsEnabled(); - - Toolkit::AccessibilityManager accessibilityManager = Toolkit::AccessibilityManager::Get(); - std::string keyName = event.GetKeyName(); if( mIsFocusIndicatorShown == UNKNOWN ) @@ -764,7 +758,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) { if (keyName == "Left") { - if(!isAccessibilityEnabled) + if(!mIsFocusIndicatorShown) { if(mIsFocusIndicatorShown == HIDE) { @@ -781,13 +775,15 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) } else { - // Move the accessibility focus backward - accessibilityManager.MoveFocusBackward(); + // Move the focus towards left + MoveFocus(Toolkit::Control::KeyboardFocus::LEFT); } + + isFocusStartableKey = true; } else if (keyName == "Right") { - if(!isAccessibilityEnabled) + if(!mIsFocusIndicatorShown) { if( mIsFocusIndicatorShown == HIDE ) { @@ -802,13 +798,13 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) } else { - // Move the accessibility focus forward - accessibilityManager.MoveFocusForward(); + // Move the focus towards right + MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT); } isFocusStartableKey = true; } - else if (keyName == "Up" && !isAccessibilityEnabled) + else if (keyName == "Up") { if( mIsFocusIndicatorShown == HIDE ) { @@ -823,7 +819,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "Down" && !isAccessibilityEnabled) + else if (keyName == "Down") { if( mIsFocusIndicatorShown == HIDE ) { @@ -838,7 +834,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "Prior" && !isAccessibilityEnabled) + else if (keyName == "Prior") { if( mIsFocusIndicatorShown == HIDE ) { @@ -853,7 +849,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "Next" && !isAccessibilityEnabled) + else if (keyName == "Next") { if( mIsFocusIndicatorShown == HIDE ) { @@ -868,7 +864,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "Tab" && !isAccessibilityEnabled) + else if (keyName == "Tab") { if( mIsFocusIndicatorShown == HIDE ) { @@ -884,7 +880,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "space" && !isAccessibilityEnabled) + else if (keyName == "space") { if( mIsFocusIndicatorShown == HIDE ) { @@ -894,7 +890,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "" && !isAccessibilityEnabled) + else if (keyName == "") { // Check the fake key event for evas-plugin case if( mIsFocusIndicatorShown == HIDE ) @@ -905,11 +901,11 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) isFocusStartableKey = true; } - else if (keyName == "Backspace" && !isAccessibilityEnabled) + else if (keyName == "Backspace") { // Emit signal to go back to the previous view??? } - else if (keyName == "Escape" && !isAccessibilityEnabled) + else if (keyName == "Escape") { } } @@ -917,7 +913,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) { if (keyName == "Return") { - if((mIsFocusIndicatorShown == HIDE) && !isAccessibilityEnabled) + if( mIsFocusIndicatorShown == HIDE ) { // Show focus indicator mIsFocusIndicatorShown = SHOW; @@ -925,16 +921,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) else { // The focused actor has enter pressed on it - Actor actor; - if( !isAccessibilityEnabled ) - { - actor = GetCurrentFocusActor(); - } - else - { - actor = accessibilityManager.GetCurrentFocusActor(); - } - + Actor actor = GetCurrentFocusActor(); if( actor ) { DoKeyboardEnter( actor ); @@ -945,7 +932,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) } } - if(isFocusStartableKey && ( mIsFocusIndicatorShown == SHOW ) && !isAccessibilityEnabled) + if( isFocusStartableKey && mIsFocusIndicatorShown == SHOW ) { Actor actor = GetCurrentFocusActor(); if( actor ) @@ -962,6 +949,7 @@ void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event) // Let's try to move the initial focus MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT); } + } } diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index 0cd6adb..b0aa82e 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -35,6 +35,7 @@ #include #include #include +#include using namespace Dali; @@ -246,6 +247,11 @@ bool Controller::Impl::ProcessInputEvents() GetCursorPosition( mEventData->mPrimaryCursorPosition, cursorInfo ); + if( NULL != mEditableControlInterface ) + { + mEditableControlInterface->CaretMoved( mEventData->mPrimaryCursorPosition ); + } + if( mEventData->mUpdateCursorHookPosition ) { // Update the cursor hook position. Used to move the cursor with the keys 'up' and 'down'. @@ -1519,6 +1525,18 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete } } +void Controller::Impl::SetSelection( int start, int end ) +{ + mEventData->mLeftSelectionPosition = start; + mEventData->mRightSelectionPosition = end; + mEventData->mUpdateCursorPosition = true; +} + +std::pair< int, int > Controller::Impl::GetSelectionIndexes() const +{ + return { mEventData->mLeftSelectionPosition, mEventData->mRightSelectionPosition }; +} + void Controller::Impl::ShowClipboard() { if( mClipboard ) @@ -1540,7 +1558,7 @@ void Controller::Impl::SetClipboardHideEnable(bool enable) mClipboardHideEnabled = enable; } -bool Controller::Impl::CopyStringToClipboard( std::string& source ) +bool Controller::Impl::CopyStringToClipboard( const std::string& source ) { //Send string to clipboard return ( mClipboard && mClipboard.SetItem( source ) ); diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index fc30d7b..61714e6 100755 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -656,13 +656,17 @@ struct Controller::Impl */ void RetrieveSelection( std::string& selectedText, bool deleteAfterRetrieval ); + void SetSelection( int start, int end ); + + std::pair< int, int > GetSelectionIndexes() const; + void ShowClipboard(); void HideClipboard(); void SetClipboardHideEnable(bool enable); - bool CopyStringToClipboard( std::string& source ); + bool CopyStringToClipboard( const std::string& source ); void SendSelectionToClipboard( bool deleteAfterSending ); diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp old mode 100755 new mode 100644 index 6fe0d0c..aed8d32 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -733,6 +733,31 @@ void Controller::UpdateAfterFontChange( const std::string& newDefaultFont ) } } +void Controller::RetrieveSelection( std::string& selectedText ) const +{ + mImpl->RetrieveSelection( selectedText, false ); +} + +void Controller::SetSelection( int start, int end ) +{ + mImpl->SetSelection( start, end ); +} + +std::pair< int, int > Controller::GetSelectionIndexes() const +{ + return mImpl->GetSelectionIndexes(); +} + +void Controller::CopyStringToClipboard( const std::string& source ) +{ + mImpl->CopyStringToClipboard( source ); +} + +void Controller::SendSelectionToClipboard( bool deleteAfterSending ) +{ + mImpl->SendSelectionToClipboard( deleteAfterSending ); +} + // public : Default style & Input style void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily ) @@ -2497,13 +2522,17 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ // Insert at current cursor position. Vector& modifyText = mImpl->mModel->mLogicalModel->mText; + auto pos = modifyText.End(); if( cursorIndex < numberOfCharactersInModel ) { - modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + pos = modifyText.Begin() + cursorIndex; } - else + unsigned int realPos = pos - modifyText.Begin(); + modifyText.Insert( pos, utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + + if( NULL != mImpl->mEditableControlInterface ) { - modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText ); + mImpl->mEditableControlInterface->TextInserted( realPos, maxSizeOfNewText, text ); } // Mark the first paragraph to be updated. @@ -2669,6 +2698,13 @@ bool Controller::RemoveText( int cursorOffset, Vector::Iterator first = currentText.Begin() + cursorIndex; Vector::Iterator last = first + numberOfCharacters; + if( NULL != mImpl->mEditableControlInterface ) + { + std::string utf8; + Utf32ToUtf8( first, numberOfCharacters, utf8 ); + mImpl->mEditableControlInterface->TextDeleted( cursorIndex, numberOfCharacters, utf8 ); + } + currentText.Erase( first, last ); // Cursor position retreat @@ -3094,6 +3130,14 @@ void Controller::ResetCursorPosition( CharacterIndex cursorIndex ) } } +CharacterIndex Controller::GetCursorPosition() +{ + if( !mImpl->mEventData ) + return 0; + + return mImpl->mEventData->mPrimaryCursorPosition; +} + void Controller::ResetScrollPosition() { if( NULL != mImpl->mEventData ) diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h old mode 100755 new mode 100644 index 6bd8706..d627324 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -662,6 +662,38 @@ public: // Update. */ void UpdateAfterFontChange( const std::string& newDefaultFont ); + /** + * @brief The method acquires currently selected text + * @param selectedText variable to place selected text in + */ + void RetrieveSelection( std::string& selectedText ) const; + + /** + * @brief The method sets selection in given range + * @param start index of first character + * @param end index of first character after selection + */ + void SetSelection( int start, int end ); + + /** + * @brief This method retrieve indexes of current selection + * + * @return a pair, where first element is left index of selection and second is the right one + */ + std::pair< int, int > GetSelectionIndexes() const; + + /** + * Place string in system clipboard + * @param source std::string + */ + void CopyStringToClipboard( const std::string& source ); + + /** + * Place currently selected text in system clipboard + * @param deleteAfterSending flag pointing if text should be deleted after sending to clipboard + */ + void SendSelectionToClipboard( bool deleteAfterSending ); + public: // Default style & Input style /** @@ -1573,6 +1605,19 @@ public: // Text-input Event Queuing. */ Actor CreateBackgroundActor(); + /** + * @brief Used to reset the cursor position after setting a new text. + * + * @param[in] cursorIndex Where to place the cursor. + */ + void ResetCursorPosition( CharacterIndex cursorIndex ); + + /** + * @brief The method acquires current position of cursor + * @return unsigned value with cursor position + */ + CharacterIndex GetCursorPosition(); + protected: // Inherit from Text::Decorator::ControllerInterface. /** @@ -1717,13 +1762,6 @@ private: // Helpers. void ClearStyleData(); /** - * @brief Used to reset the cursor position after setting a new text. - * - * @param[in] cursorIndex Where to place the cursor. - */ - void ResetCursorPosition( CharacterIndex cursorIndex ); - - /** * @brief Used to reset the scroll position after setting a new text. */ void ResetScrollPosition(); diff --git a/dali-toolkit/internal/text/text-editable-control-interface.h b/dali-toolkit/internal/text/text-editable-control-interface.h index abfbb59..6239a68 100644 --- a/dali-toolkit/internal/text/text-editable-control-interface.h +++ b/dali-toolkit/internal/text/text-editable-control-interface.h @@ -46,6 +46,21 @@ public: {} /** + * @brief Called to signal that text has been inserted. + */ + virtual void TextInserted( unsigned int position, unsigned int length, const std::string &content ) = 0; + + /** + * @brief Called to signal that text has been deleted. + */ + virtual void TextDeleted( unsigned int position, unsigned int length, const std::string &content ) = 0; + + /** + * @brief Called to signal that caret (cursor position) has been moved. + */ + virtual void CaretMoved( unsigned int position ) = 0; + + /** * @brief Called to signal that text has been inserted or deleted. */ virtual void TextChanged() = 0; diff --git a/dali-toolkit/public-api/controls/control-impl.cpp b/dali-toolkit/public-api/controls/control-impl.cpp index b4bb4da..c34dbb3 100644 --- a/dali-toolkit/public-api/controls/control-impl.cpp +++ b/dali-toolkit/public-api/controls/control-impl.cpp @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include // INTERNAL INCLUDES #include @@ -45,6 +48,9 @@ #include #include #include +#include +#include +#include namespace Dali { @@ -234,6 +240,7 @@ void Control::EnableGestureDetection(GestureType::Value type) if((type & GestureType::PAN) && !mImpl->mPanGestureDetector) { mImpl->mPanGestureDetector = PanGestureDetector::New(); + mImpl->mPanGestureDetector.SetMaximumTouchesRequired(2); mImpl->mPanGestureDetector.DetectedSignal().Connect(mImpl, &Impl::PanDetected); mImpl->mPanGestureDetector.Attach(Self()); } @@ -367,7 +374,11 @@ void Control::KeyboardEnter() bool Control::OnAccessibilityActivated() { - return false; // Accessibility activation is not handled by default + if( Toolkit::KeyboardFocusManager::Get().SetCurrentFocusActor( Self() ) ) + { + return OnKeyboardEnter(); + } + return false; } bool Control::OnKeyboardEnter() @@ -476,6 +487,17 @@ void Control::Initialize() { SetKeyboardNavigationSupport(true); } + + Dali::TypeInfo type; + Self().GetTypeInfo( type ); + if (type) + { + auto typeName = type.GetName(); + DevelControl::AppendAccessibilityAttribute( Self(), "t", typeName ); + } + + if (Accessibility::IsUp()) + mImpl->AccessibilityRegister(); } void Control::OnInitialize() @@ -524,6 +546,17 @@ void Control::EmitKeyInputFocusSignal(bool focusGained) { Dali::Toolkit::Control handle(GetOwner()); + if( Accessibility::IsUp() ) + { + auto self = mImpl->GetAccessibilityObject( Self() ); + self->EmitFocused( focusGained ); + auto parent = self->GetParent(); + if( parent && !self->GetStates()[Dali::Accessibility::State::MANAGES_DESCENDANTS] ) + { + parent->EmitActiveDescendantChanged( parent, self ); + } + } + if(focusGained) { // signals are allocated dynamically when someone connects @@ -563,10 +596,18 @@ void Control::OnSceneConnection(int depth) // Request to be laid out when the control is connected to the Scene. // Signal that a Relayout may be needed + if( Accessibility::IsUp() ) + { + mImpl->AccessibilityRegister(); + } } void Control::OnSceneDisconnection() { + if( Accessibility::IsUp() ) + { + mImpl->AccessibilityDeregister(); + } mImpl->OnSceneDisconnection(); } @@ -592,10 +633,33 @@ void Control::OnPropertySet(Property::Index index, const Property::Value& proper { // If the clipping mode has been set, we may need to create a renderer. // Only do this if we are already on-stage as the OnSceneConnection will handle the off-stage clipping controls. - if((index == Actor::Property::CLIPPING_MODE) && Self().GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + switch( index ) { - // Note: This method will handle whether creation of the renderer is required. - CreateClippingRenderer(*this); + case Actor::Property::CLIPPING_MODE: + { + if( Self().GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE )) + { + // Note: This method will handle whether creation of the renderer is required. + CreateClippingRenderer( *this ); + } + break; + } + case Actor::Property::VISIBLE: + { + if( Dali::Accessibility::IsUp() ) + { + Dali::Accessibility::Accessible::Get(Self())->EmitVisible( Self().GetProperty( Actor::Property::VISIBLE ).Get() ); + } + break; + } + case Toolkit::DevelControl::Property::ACCESSIBILITY_ROLE: + { + if( Dali::Accessibility::IsUp() ) + { + Dali::Accessibility::Accessible::Get(Self())->Emit( Dali::Accessibility::ObjectPropertyChangeEvent::ROLE ); + } + break; + } } } diff --git a/dali-toolkit/public-api/controls/control.h b/dali-toolkit/public-api/controls/control.h index 7720d13..a7aee35 100644 --- a/dali-toolkit/public-api/controls/control.h +++ b/dali-toolkit/public-api/controls/control.h @@ -456,7 +456,6 @@ public: * @note A RelayoutRequest is queued by Control before this signal is emitted */ ResourceReadySignalType& ResourceReadySignal(); - public: // Intended for control developers /** * @brief Creates an initialized Control.