// EXTERNAL INCLUDES
#include <cstring> // for strcmp
#include <dali/public-api/actors/layer.h>
+#include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
#include <dali/devel-api/adaptor-framework/sound-player.h>
#include <dali/public-api/animation/constraints.h>
#include <dali/devel-api/events/hit-test-algorithm.h>
#include <dali-toolkit/public-api/controls/control.h>
#include <dali-toolkit/public-api/controls/control-impl.h>
#include <dali-toolkit/public-api/controls/image-view/image-view.h>
-#include <dali/devel-api/adaptor-framework/accessibility.h>
namespace Dali
{
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_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.9.png";
+
+const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
+const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "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.IsVisible()
+ && actor.GetCurrentWorldColor().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<bool>(propertyActorFocusable);
+ }
+ }
+ break;
+ }
+ case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
+ {
+ if( actor.IsVisible() ) // 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),
+ mIsWrapped(false),
+ mIsFocusWithinGroup(false),
+ mIsEndcapFeedbackEnabled(false),
+ mIsEndcapFeedbackPlayed(false),
+ mIsAccessibilityTtsEnabled(false),
+ mTtsCreated(false),
+ mIsFocusIndicatorEnabled(false),
+ mContinuousPlayMode(false)
{
}
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)
+ {
+ unsigned int actorID = actor.GetId();
+
+ ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
+ info.mAccessibilityAttributes[type] = text;
+
+ mIDAdditionalInfoContainer.erase(actorID);
+ mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
+ }
}
std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const
{
- return "";
+ std::string text;
+
+ if(actor)
+ {
+ ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
+ text = data.mAccessibilityAttributes[type];
+ }
+
+ return text;
}
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;
+
+ // Update the actor's focus order in its additional data
+ SynchronizeActorAdditionalInfo(actorID, (*iter).first);
+ }
+
+ mFocusIDContainer.erase(order);
+ }
+
+ // 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.GetId()));
+ }
+
+ // Update the actor's focus order in its additional data
+ SynchronizeActorAdditionalInfo(actor.GetId(), order);
+ }
}
unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const
{
- return 0;
+ unsigned int focusOrder = 0;
+
+ if(actor)
+ {
+ ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
+ focusOrder = data.mFocusOrder;
+ }
+
+ return focusOrder;
}
unsigned int AccessibilityManager::GenerateNewFocusOrder() const
{
- return 0;
+ unsigned int order = 1;
+ FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
+
+ if(iter != mFocusIDContainer.rend())
+ {
+ order = (*iter).first + 1;
+ }
+
+ return order;
}
Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order)
{
- return {};
+ Actor actor = Actor();
+
+ FocusIDIter focusIDIter = mFocusIDContainer.find(order);
+ if(focusIDIter != mFocusIDContainer.end())
+ {
+ Actor rootActor = Stage::GetCurrent().GetRootLayer();
+ actor = rootActor.FindChildById(mFocusIDContainer[order]);
+ }
+
+ return actor;
}
bool AccessibilityManager::SetCurrentFocusActor(Actor actor)
{
+ if(actor)
+ {
+ return DoSetCurrentFocusActor(actor.GetId());
+ }
+
+ 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());
+ }
+
+ 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<bool>(propertyActorFocusable);
+ }
+
+ // Go through the actor's hierarchy to check whether the actor is visible
+ bool actorVisible = actor.IsVisible();
+ Actor parent = actor.GetParent();
+ while (actorVisible && parent && parent != rootActor)
+ {
+ actorVisible = parent.IsVisible();
+ parent = parent.GetParent();
+ }
+
+ // Check whether the actor is fully transparent
+ bool actorOpaque = actor.GetCurrentWorldColor().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)
+ {
+ soundPlayer.PlaySound(FOCUS_SOUND_FILE);
+ }
+
+ // 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;
}
Actor AccessibilityManager::GetCurrentFocusActor()
{
- return {};
+ Actor rootActor = Stage::GetCurrent().GetRootLayer();
+ return rootActor.FindChildById(mCurrentFocusActor.second);
}
Actor AccessibilityManager::GetCurrentFocusGroup()
{
- return {};
+ return GetFocusGroup(GetCurrentFocusActor());
}
unsigned int AccessibilityManager::GetCurrentFocusOrder()
{
- return 0;
+ return mCurrentFocusActor.first;
}
bool AccessibilityManager::MoveFocusForward()
{
- return false;
+ 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, 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);
+ }
+ }
+
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
+
+ return ret;
}
bool AccessibilityManager::MoveFocusBackward()
{
- return false;
+ 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);
+ }
+ }
+
+ DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
+
+ return ret;
+}
+
+void AccessibilityManager::DoActivate(Actor actor)
+{
+ 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);
+ }
}
void AccessibilityManager::ClearFocus()
{
+ 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());
+
+ if(mIsAccessibilityTtsEnabled)
+ {
+ // Stop the TTS playing if any
+ Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
+ player.Stop();
+ }
}
void AccessibilityManager::Reset()
{
+ ClearFocus();
+ mFocusIDContainer.clear();
+ mIDAdditionalInfoContainer.clear();
}
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
{
- return false;
+ // 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<bool>(propertyIsFocusGroup);
+ }
+ }
+
+ return isFocusGroup;
}
Actor AccessibilityManager::GetFocusGroup(Actor actor)
{
- return {};
+ // Go through the actor's hierarchy to check which focus group the actor belongs to
+ while (actor && !IsFocusGroup(actor))
+ {
+ actor = actor.GetParent();
+ }
+
+ return actor;
}
Vector2 AccessibilityManager::GetReadPosition() const
{
- return {};
+ AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
+ return adaptor.GetReadPosition();
}
void AccessibilityManager::SetGroupMode(bool enabled)
{
+ mIsFocusWithinGroup = enabled;
}
bool AccessibilityManager::GetGroupMode() const
{
- return false;
+ return mIsFocusWithinGroup;
}
void AccessibilityManager::SetWrapMode(bool wrapped)
{
+ mIsWrapped = wrapped;
}
bool AccessibilityManager::GetWrapMode() const
{
- return false;
+ return mIsWrapped;
}
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;
+ }
}
Actor AccessibilityManager::GetFocusIndicatorActor()
{
- return {};
+ if( ! mFocusIndicatorActor )
+ {
+ // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
+ mFocusIndicatorActor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH );
+ mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
+ mFocusIndicatorActor.SetZ( 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)
+ {
+ soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
+ }
+
+ 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& touchEvent )
+{
+ Dali::Toolkit::AccessibilityManager handle( this );
+ if( !mActionScrollSignal.Empty() )
+ {
+ mActionScrollSignal.Emit( handle, touchEvent );
+ }
+
+ 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::AccessibilityActionTouch(const TouchEvent& touchEvent)
+{
+ bool handled = false;
+
+ // TODO: Need to convert the touchevent for the focused actor?
+
+ Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
+ if(control)
+ {
+ handled = GetImplementation( control ).OnAccessibilityTouch(touchEvent);
+ }
+
+ return handled;
+}
+
+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");
+ }
+ }
+
+ // Gesture::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 Gesture::Finished iteration.
+ mPreviousPosition = panEvent.previousPosition;
+ }
+
+ Actor rootActor = Stage::GetCurrent().GetRootLayer();
+
+ Dali::PanGesture pan( static_cast<Dali::Gesture::State>(panEvent.state) );
+
+ pan.time = panEvent.time;
+ pan.numberOfTouches = panEvent.numberOfTouches;
+ pan.screenPosition = panEvent.currentPosition;
+ pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
+ pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
+ pan.screenVelocity.y = pan.screenDisplacement.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 );
+ pan.position = localCurrent;
+
+ Vector2 localPrevious;
+ control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
+
+ pan.displacement = localCurrent - localPrevious;
+ pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
+ pan.velocity.y = pan.displacement.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;
}
Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
// EXTERNAL INCLUDES
#include <string>
#include <dali/devel-api/common/map-wrapper.h>
+#include <dali/devel-api/adaptor-framework/accessibility-action-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
#include <dali/public-api/object/base-object.h>
// INTERNAL INCLUDES
/**
* @copydoc Toolkit::AccessibilityManager
*/
-class AccessibilityManager : public Dali::BaseObject, public Dali::ConnectionTracker
+class AccessibilityManager : public Dali::BaseObject, Dali::AccessibilityActionHandler, Dali::AccessibilityGestureHandler, public Dali::ConnectionTracker
{
public:
virtual ~AccessibilityManager();
private:
- AccessibilityActionSignalType mStatusChangedSignal;
- AccessibilityActionSignalType mActionNextSignal;
- AccessibilityActionSignalType mActionPreviousSignal;
- AccessibilityActionSignalType mActionActivateSignal;
- AccessibilityActionSignalType mActionOverSignal;
- AccessibilityActionSignalType mActionReadSignal;
- AccessibilityActionSignalType mActionReadNextSignal;
- AccessibilityActionSignalType mActionReadPreviousSignal;
- AccessibilityActionSignalType mActionUpSignal;
- AccessibilityActionSignalType mActionDownSignal;
- AccessibilityActionSignalType mActionClearFocusSignal;
- AccessibilityActionSignalType mActionBackSignal;
- AccessibilityActionSignalType mActionScrollUpSignal;
- AccessibilityActionSignalType mActionScrollDownSignal;
- AccessibilityActionSignalType mActionPageLeftSignal;
- AccessibilityActionSignalType mActionPageRightSignal;
- AccessibilityActionSignalType mActionPageUpSignal;
- AccessibilityActionSignalType mActionPageDownSignal;
- AccessibilityActionSignalType mActionMoveToFirstSignal;
- AccessibilityActionSignalType mActionMoveToLastSignal;
- AccessibilityActionSignalType mActionReadFromTopSignal;
- AccessibilityActionSignalType mActionReadFromNextSignal;
- AccessibilityActionSignalType mActionZoomSignal;
- AccessibilityActionSignalType mActionReadIndicatorInformationSignal;
- AccessibilityActionSignalType mActionReadPauseResumeSignal;
- AccessibilityActionSignalType mActionStartStopSignal;
+
+ /**
+ * 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.
+ */
+ virtual bool HandlePanGesture(const AccessibilityGestureEvent& panEvent);
+
+ /**
+ * Change the accessibility status when Accessibility feature(screen-reader) turned on or off.
+ * @return whether the status is changed or not.
+ */
+ virtual bool ChangeAccessibilityStatus();
+
+ /**
+ * Clear the accessibility focus from the current focused actor.
+ * @return whether the focus is cleared or not.
+ */
+ virtual bool ClearAccessibilityFocus();
+
+ /**
+ * Perform the accessibility action associated with a scroll event.
+ * @param touchEvent The touch point (and time) of the event.
+ * @return whether the focus is cleared or not.
+ */
+ virtual bool AccessibilityActionScroll( Dali::TouchEvent& touchEvent );
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionPrevious(bool allowEndFeedback);
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionNext(bool allowEndFeedback);
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionReadPrevious(bool allowEndFeedback);
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionReadNext(bool allowEndFeedback);
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionRead(bool allowReadAgain);
+
+ /**
+ * Perform the accessibility action to activate the current focused actor (by one finger double tap).
+ * @return whether the accessibility action is performed or not.
+ */
+ virtual bool AccessibilityActionActivate();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionUp();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionDown();
+
+ /**
+ * Perform the accessibility action to navigate back (by two fingers circle draw).
+ * @return whether the accessibility action is performed or not.
+ */
+ virtual bool AccessibilityActionBack();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionScrollUp();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionScrollDown();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionPageLeft();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionPageRight();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionPageUp();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionPageDown();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionMoveToFirst();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionMoveToLast();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionReadFromTop();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionReadFromNext();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionZoom();
+
+ /**
+ * 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.
+ */
+ virtual bool AccessibilityActionReadPauseResume();
+
+ /**
+ * Perform the accessibility action to start/stop the current action (by two fingers double tap).
+ * @return whether the accessibility action is performed or not.
+ */
+ virtual bool AccessibilityActionStartStop();
+
+ /**
+ * Perform the accessibility action to mouse move (by one finger tap & hold and move).
+ * @param touchEvent touch event structure
+ * @return whether the accessibility action is performed or not.
+ */
+ virtual bool AccessibilityActionTouch(const TouchEvent& touchEvent);
+
+ /**
+ * 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&);
+
+ AccessibilityManager& operator=(const AccessibilityManager& rhs);
+
+private:
+
+ 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
+
+ // Action signals.
+ AccessibilityActionSignalType mStatusChangedSignal;
+ AccessibilityActionSignalType mActionNextSignal;
+ AccessibilityActionSignalType mActionPreviousSignal;
+ AccessibilityActionSignalType mActionActivateSignal;
+ AccessibilityActionSignalType mActionOverSignal;
+ AccessibilityActionSignalType mActionReadSignal;
+ AccessibilityActionSignalType mActionReadNextSignal;
+ AccessibilityActionSignalType mActionReadPreviousSignal;
+ AccessibilityActionSignalType mActionUpSignal;
+ AccessibilityActionSignalType mActionDownSignal;
+ AccessibilityActionSignalType mActionClearFocusSignal;
+ AccessibilityActionSignalType mActionBackSignal;
+ AccessibilityActionSignalType mActionScrollUpSignal;
+ AccessibilityActionSignalType mActionScrollDownSignal;
+ AccessibilityActionSignalType mActionPageLeftSignal;
+ AccessibilityActionSignalType mActionPageRightSignal;
+ AccessibilityActionSignalType mActionPageUpSignal;
+ AccessibilityActionSignalType mActionPageDownSignal;
+ AccessibilityActionSignalType mActionMoveToFirstSignal;
+ AccessibilityActionSignalType mActionMoveToLastSignal;
+ AccessibilityActionSignalType mActionReadFromTopSignal;
+ AccessibilityActionSignalType mActionReadFromNextSignal;
+ AccessibilityActionSignalType mActionZoomSignal;
+ AccessibilityActionSignalType mActionReadIndicatorInformationSignal;
+ AccessibilityActionSignalType mActionReadPauseResumeSignal;
+ AccessibilityActionSignalType mActionStartStopSignal;
AccessibilityActionScrollSignalType mActionScrollSignal;
- Toolkit::AccessibilityManager::FocusChangedSignalType mFocusChangedSignal;
- Toolkit::AccessibilityManager::FocusOvershotSignalType mFocusOvershotSignal;
- Toolkit::AccessibilityManager::FocusedActorActivatedSignalType mFocusedActorActivatedSignal;
+
+ 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 Gesture::Finished events
+ unsigned int mRecursiveFocusMoveCounter; ///< The counter to count the number of recursive focus movement attempted before the focus movement is successful.
+
+ 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
+
};
} // namespace Internal