2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "accessibility-manager-impl.h"
22 #include <cstring> // for strcmp
23 #include <dali/public-api/actors/layer.h>
24 #include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
25 #include <dali/devel-api/adaptor-framework/sound-player.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/devel-api/events/hit-test-algorithm.h>
28 #include <dali/public-api/images/resource-image.h>
29 #include <dali/integration-api/debug.h>
32 #include <dali-toolkit/public-api/controls/control.h>
33 #include <dali-toolkit/public-api/controls/control-impl.h>
34 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
45 namespace // unnamed namespace
50 const char* const SIGNAL_FOCUS_CHANGED = "focusChanged";
51 const char* const SIGNAL_FOCUS_OVERSHOT = "focusOvershot";
52 const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focusedActorActivated";
54 #if defined(DEBUG_ENABLED)
55 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
58 const char* const ACTOR_FOCUSABLE("focusable");
59 const char* const IS_FOCUS_GROUP("isFocusGroup");
61 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.9.png";
63 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
64 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
67 * The function to be used in the hit-test algorithm to check whether the actor is hittable.
69 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
71 bool hittable = false;
75 case Dali::HitTestAlgorithm::CHECK_ACTOR:
77 // Check whether the actor is visible and not fully transparent.
79 && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
81 // Check whether the actor is focusable
82 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
83 if(propertyActorFocusable != Property::INVALID_INDEX)
85 hittable = actor.GetProperty<bool>(propertyActorFocusable);
90 case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
92 if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
109 AccessibilityManager::AccessibilityManager()
110 : mCurrentFocusActor(FocusIDPair(0, 0)),
111 mCurrentGesturedActor(),
112 mFocusIndicatorActor(),
113 mPreviousPosition( 0.0f, 0.0f ),
114 mRecursiveFocusMoveCounter(0),
116 mIsFocusWithinGroup(false),
117 mIsEndcapFeedbackEnabled(false),
118 mIsEndcapFeedbackPlayed(false),
119 mIsAccessibilityTtsEnabled(false),
121 mIsFocusIndicatorEnabled(false),
122 mContinuousPlayMode(false)
126 AccessibilityManager::~AccessibilityManager()
130 void AccessibilityManager::Initialise()
132 AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
133 adaptor.SetActionHandler(*this);
134 adaptor.SetGestureHandler(*this);
136 ChangeAccessibilityStatus();
139 AccessibilityManager::ActorAdditionalInfo AccessibilityManager::GetActorAdditionalInfo(const unsigned int actorID) const
141 ActorAdditionalInfo data;
142 IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
143 if(iter != mIDAdditionalInfoContainer.end())
145 data = (*iter).second;
151 void AccessibilityManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
153 ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
154 actorInfo.mFocusOrder = order;
155 mIDAdditionalInfoContainer.erase(actorID);
156 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
159 void AccessibilityManager::SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text)
163 unsigned int actorID = actor.GetId();
165 ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
166 info.mAccessibilityAttributes[type] = text;
168 mIDAdditionalInfoContainer.erase(actorID);
169 mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
173 std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const
179 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
180 text = data.mAccessibilityAttributes[type];
186 void AccessibilityManager::SetFocusOrder(Actor actor, const unsigned int order)
188 // Do nothing if the focus order of the actor is not changed.
189 if(actor && GetFocusOrder(actor) != order)
191 // Firstly delete the actor from the focus chain if it's already there with a different focus order.
192 mFocusIDContainer.erase(GetFocusOrder(actor));
194 // Create/retrieve actor focusable property
195 Property::Index propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE );
199 // The actor is not focusable without a defined focus order.
200 actor.SetProperty(propertyActorFocusable, false);
202 // If the actor is currently being focused, it should clear the focus
203 if(actor == GetCurrentFocusActor())
208 else // Insert the actor to the focus chain
210 // Check whether there is another actor in the focus chain with the same focus order already.
211 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
212 if(focusIDIter != mFocusIDContainer.end())
214 // We need to increase the focus order of that actor and all the actors followed it
215 // in the focus chain.
216 FocusIDIter lastIter = mFocusIDContainer.end();
217 --lastIter;//We want forward iterator to the last element here
218 mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
220 // Update the actor's focus order in its additional data
221 SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
223 for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
225 FocusIDIter previousIter = iter;
226 --previousIter;//We want forward iterator to the previous element here
227 unsigned int actorID = (*previousIter).second;
228 (*iter).second = actorID;
230 // Update the actor's focus order in its additional data
231 SynchronizeActorAdditionalInfo(actorID, (*iter).first);
234 mFocusIDContainer.erase(order);
237 // The actor is focusable
238 actor.SetProperty(propertyActorFocusable, true);
240 // Now we insert the actor into the focus chain with the specified focus order
241 mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
244 // Update the actor's focus order in its additional data
245 SynchronizeActorAdditionalInfo(actor.GetId(), order);
249 unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const
251 unsigned int focusOrder = 0;
255 ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
256 focusOrder = data.mFocusOrder;
262 unsigned int AccessibilityManager::GenerateNewFocusOrder() const
264 unsigned int order = 1;
265 FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
267 if(iter != mFocusIDContainer.rend())
269 order = (*iter).first + 1;
275 Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order)
277 Actor actor = Actor();
279 FocusIDIter focusIDIter = mFocusIDContainer.find(order);
280 if(focusIDIter != mFocusIDContainer.end())
282 Actor rootActor = Stage::GetCurrent().GetRootLayer();
283 actor = rootActor.FindChildById(mFocusIDContainer[order]);
289 bool AccessibilityManager::SetCurrentFocusActor(Actor actor)
293 return DoSetCurrentFocusActor(actor.GetId());
299 bool AccessibilityManager::DoSetCurrentFocusActor(const unsigned int actorID)
301 Actor rootActor = Stage::GetCurrent().GetRootLayer();
303 // If the group mode is enabled, check which focus group the current focused actor belongs to
305 if(mIsFocusWithinGroup)
307 focusGroup = GetFocusGroup(GetCurrentFocusActor());
312 focusGroup = rootActor;
315 Actor actor = focusGroup.FindChildById(actorID);
317 // Check whether the actor is in the stage
320 // Check whether the actor is focusable
321 bool actorFocusable = false;
322 Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
323 if(propertyActorFocusable != Property::INVALID_INDEX)
325 actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
328 // Go through the actor's hierarchy to check whether the actor is visible
329 bool actorVisible = actor.IsVisible();
330 Actor parent = actor.GetParent();
331 while (actorVisible && parent && parent != rootActor)
333 actorVisible = parent.IsVisible();
334 parent = parent.GetParent();
337 // Check whether the actor is fully transparent
338 bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
340 // Set the focus only when the actor is focusable and visible and not fully transparent
341 if(actorVisible && actorFocusable && actorOpaque)
343 // Draw the focus indicator upon the focused actor
344 if( mIsFocusIndicatorEnabled )
346 actor.Add( GetFocusIndicatorActor() );
349 // Send notification for the change of focus actor
350 mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
352 // Save the current focused actor
353 mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
355 if(mIsAccessibilityTtsEnabled)
357 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
360 soundPlayer.PlaySound(FOCUS_SOUND_FILE);
363 // Play the accessibility attributes with the TTS player.
364 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
366 // Combine attribute texts to one text
367 std::string informationText;
368 for(int i = 0; i < Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
370 if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
374 informationText += ", "; // for space time between each information
376 informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
379 player.Play(informationText);
386 DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
390 Actor AccessibilityManager::GetCurrentFocusActor()
392 Actor rootActor = Stage::GetCurrent().GetRootLayer();
393 return rootActor.FindChildById(mCurrentFocusActor.second);
396 Actor AccessibilityManager::GetCurrentFocusGroup()
398 return GetFocusGroup(GetCurrentFocusActor());
401 unsigned int AccessibilityManager::GetCurrentFocusOrder()
403 return mCurrentFocusActor.first;
406 bool AccessibilityManager::MoveFocusForward()
409 mRecursiveFocusMoveCounter = 0;
411 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
412 if(focusIDIter != mFocusIDContainer.end())
414 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
415 ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
419 // TODO: if there is not focused actor, move first actor
420 if(!mFocusIDContainer.empty())
422 //if there is not focused actor, move 1st actor
423 focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
424 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
425 ret = DoSetCurrentFocusActor((*focusIDIter).second);
429 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
434 bool AccessibilityManager::MoveFocusBackward()
437 mRecursiveFocusMoveCounter = 0;
439 FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
440 if(focusIDIter != mFocusIDContainer.end())
442 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
443 ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
447 // TODO: if there is not focused actor, move last actor
448 if(!mFocusIDContainer.empty())
450 //if there is not focused actor, move last actor
451 focusIDIter = mFocusIDContainer.end();
452 --focusIDIter;//We want forward iterator to the last element here
453 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
454 ret = DoSetCurrentFocusActor((*focusIDIter).second);
458 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
463 void AccessibilityManager::DoActivate(Actor actor)
467 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
470 // Notify the control that it is activated
471 GetImplementation( control ).AccessibilityActivate();
474 // Send notification for the activation of focused actor
475 mFocusedActorActivatedSignal.Emit(actor);
479 void AccessibilityManager::ClearFocus()
481 Actor actor = GetCurrentFocusActor();
482 if( actor && mFocusIndicatorActor )
484 actor.Remove( mFocusIndicatorActor );
487 mCurrentFocusActor = FocusIDPair(0, 0);
489 // Send notification for the change of focus actor
490 mFocusChangedSignal.Emit(actor, Actor());
492 if(mIsAccessibilityTtsEnabled)
494 // Stop the TTS playing if any
495 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
500 void AccessibilityManager::Reset()
503 mFocusIDContainer.clear();
504 mIDAdditionalInfoContainer.clear();
507 void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup)
511 // Create/Set focus group property.
512 actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
516 bool AccessibilityManager::IsFocusGroup(Actor actor) const
518 // Check whether the actor is a focus group
519 bool isFocusGroup = false;
523 Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
524 if(propertyIsFocusGroup != Property::INVALID_INDEX)
526 isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
533 Actor AccessibilityManager::GetFocusGroup(Actor actor)
535 // Go through the actor's hierarchy to check which focus group the actor belongs to
536 while (actor && !IsFocusGroup(actor))
538 actor = actor.GetParent();
544 Vector2 AccessibilityManager::GetReadPosition() const
546 AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
547 return adaptor.GetReadPosition();
550 void AccessibilityManager::SetGroupMode(bool enabled)
552 mIsFocusWithinGroup = enabled;
555 bool AccessibilityManager::GetGroupMode() const
557 return mIsFocusWithinGroup;
560 void AccessibilityManager::SetWrapMode(bool wrapped)
562 mIsWrapped = wrapped;
565 bool AccessibilityManager::GetWrapMode() const
570 void AccessibilityManager::SetFocusIndicatorActor(Actor indicator)
572 if( mFocusIndicatorActor != indicator )
574 Actor currentFocusActor = GetCurrentFocusActor();
575 if( currentFocusActor )
577 // The new focus indicator should be added to the current focused actor immediately
578 if( mFocusIndicatorActor )
580 currentFocusActor.Remove( mFocusIndicatorActor );
585 currentFocusActor.Add( indicator );
589 mFocusIndicatorActor = indicator;
593 Actor AccessibilityManager::GetFocusIndicatorActor()
595 if( ! mFocusIndicatorActor )
597 // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
598 mFocusIndicatorActor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH );
599 mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
600 mFocusIndicatorActor.SetZ( 1.0f );
602 // Apply size constraint to the focus indicator
603 mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
606 return mFocusIndicatorActor;
609 bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
611 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
612 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
614 if( (forward && ++focusIDIter == mFocusIDContainer.end())
615 || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
617 if(mIsEndcapFeedbackEnabled)
619 if(mIsEndcapFeedbackPlayed == false)
621 // play sound & skip moving once
622 Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
625 soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
628 mIsEndcapFeedbackPlayed = true;
631 mIsEndcapFeedbackPlayed = false;
638 focusIDIter = mFocusIDContainer.begin();
642 focusIDIter = mFocusIDContainer.end();
643 --focusIDIter;//We want forward iterator to the last element here
648 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
649 // Send notification for handling overshooted situation
650 mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS);
652 return false; // Try to move the focus out of the scope
657 if( focusIDIter == mFocusIDContainer.end() )
662 // Note: This function performs the focus change.
663 if( !DoSetCurrentFocusActor( (*focusIDIter).second ) )
665 mRecursiveFocusMoveCounter++;
666 if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
668 // We've attempted to focus all the actors in the whole focus chain and no actor
669 // can be focused successfully.
670 DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
676 return DoMoveFocus(focusIDIter, forward, wrapped);
683 void AccessibilityManager::SetFocusable(Actor actor, bool focusable)
687 // Create/Set actor focusable property.
688 actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
692 bool AccessibilityManager::ChangeAccessibilityStatus()
694 AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
695 mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
696 Dali::Toolkit::AccessibilityManager handle( this );
698 if(mIsAccessibilityTtsEnabled)
700 // Show indicator when tts turned on if there is focused actor.
701 Actor actor = GetCurrentFocusActor();
704 actor.Add( GetFocusIndicatorActor() );
706 mIsFocusIndicatorEnabled = true;
708 // Connect a signal to the TTS player to implement continuous reading mode.
709 Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
710 player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
715 // Hide indicator when tts turned off
716 Actor actor = GetCurrentFocusActor();
717 if( actor && mFocusIndicatorActor )
719 actor.Remove( mFocusIndicatorActor );
721 mIsFocusIndicatorEnabled = false;
725 // Disconnect the TTS state change signal.
726 Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
727 player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
732 mStatusChangedSignal.Emit( handle );
737 bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
739 Dali::Toolkit::AccessibilityManager handle( this );
740 if( !mActionNextSignal.Empty() )
742 mActionNextSignal.Emit( handle );
745 if(mIsAccessibilityTtsEnabled)
747 mIsEndcapFeedbackEnabled = allowEndFeedback;
748 return MoveFocusForward();
756 bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
758 Dali::Toolkit::AccessibilityManager handle( this );
759 if( !mActionPreviousSignal.Empty() )
761 mActionPreviousSignal.Emit( handle );
764 if(mIsAccessibilityTtsEnabled)
766 mIsEndcapFeedbackEnabled = allowEndFeedback;
767 return MoveFocusBackward();
775 bool AccessibilityManager::AccessibilityActionActivate()
777 Dali::Toolkit::AccessibilityManager handle( this );
778 if( !mActionActivateSignal.Empty() )
780 mActionActivateSignal.Emit( handle );
785 Actor actor = GetCurrentFocusActor();
795 bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
797 Dali::Toolkit::AccessibilityManager handle( this );
801 if ( !mActionReadSignal.Empty() )
803 mActionReadSignal.Emit( handle );
808 if ( !mActionOverSignal.Empty() )
810 mActionOverSignal.Emit( handle );
816 if(mIsAccessibilityTtsEnabled)
818 // Find the focusable actor at the read position
819 AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
820 Dali::HitTestAlgorithm::Results results;
821 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
823 FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
824 if(focusIDIter != mFocusIDContainer.end())
826 if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
828 // Move the focus to the actor
829 ret = SetCurrentFocusActor(results.actor);
830 DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
838 bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
840 Dali::Toolkit::AccessibilityManager handle( this );
841 if( !mActionReadNextSignal.Empty() )
843 mActionReadNextSignal.Emit( handle );
846 if(mIsAccessibilityTtsEnabled)
848 return MoveFocusForward();
856 bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
858 Dali::Toolkit::AccessibilityManager handle( this );
859 if( !mActionReadPreviousSignal.Empty() )
861 mActionReadPreviousSignal.Emit( handle );
864 if(mIsAccessibilityTtsEnabled)
866 return MoveFocusBackward();
874 bool AccessibilityManager::AccessibilityActionUp()
876 Dali::Toolkit::AccessibilityManager handle( this );
877 if( !mActionUpSignal.Empty() )
879 mActionUpSignal.Emit( handle );
884 if(mIsAccessibilityTtsEnabled)
886 Actor actor = GetCurrentFocusActor();
889 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
892 // Notify the control that it is activated
893 ret = GetImplementation( control ).OnAccessibilityValueChange(true);
901 bool AccessibilityManager::AccessibilityActionDown()
903 Dali::Toolkit::AccessibilityManager handle( this );
904 if( !mActionDownSignal.Empty() )
906 mActionDownSignal.Emit( handle );
911 if(mIsAccessibilityTtsEnabled)
913 Actor actor = GetCurrentFocusActor();
916 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
919 // Notify the control that it is activated
920 ret = GetImplementation( control ).OnAccessibilityValueChange(false);
928 bool AccessibilityManager::ClearAccessibilityFocus()
930 Dali::Toolkit::AccessibilityManager handle( this );
931 if( !mActionClearFocusSignal.Empty() )
933 mActionClearFocusSignal.Emit( handle );
936 if(mIsAccessibilityTtsEnabled)
947 bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touchEvent )
949 Dali::Toolkit::AccessibilityManager handle( this );
950 if( !mActionScrollSignal.Empty() )
952 mActionScrollSignal.Emit( handle, touchEvent );
958 bool AccessibilityManager::AccessibilityActionBack()
960 Dali::Toolkit::AccessibilityManager handle( this );
961 if( !mActionBackSignal.Empty() )
963 mActionBackSignal.Emit( handle );
966 // TODO: Back to previous view
968 return mIsAccessibilityTtsEnabled;
971 bool AccessibilityManager::AccessibilityActionScrollUp()
973 Dali::Toolkit::AccessibilityManager handle( this );
974 if( !mActionScrollUpSignal.Empty() )
976 mActionScrollUpSignal.Emit( handle );
981 if(mIsAccessibilityTtsEnabled)
983 Actor actor = GetCurrentFocusActor();
986 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
989 // TODO: Notify the control to scroll up. Should control handle this?
990 // ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
998 bool AccessibilityManager::AccessibilityActionScrollDown()
1000 Dali::Toolkit::AccessibilityManager handle( this );
1001 if( !mActionScrollDownSignal.Empty() )
1003 mActionScrollDownSignal.Emit( handle );
1008 if(mIsAccessibilityTtsEnabled)
1010 Actor actor = GetCurrentFocusActor();
1013 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1016 // TODO: Notify the control to scroll down. Should control handle this?
1017 // ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
1025 bool AccessibilityManager::AccessibilityActionPageLeft()
1027 Dali::Toolkit::AccessibilityManager handle( this );
1028 if( !mActionPageLeftSignal.Empty() )
1030 mActionPageLeftSignal.Emit( handle );
1035 if(mIsAccessibilityTtsEnabled)
1037 Actor actor = GetCurrentFocusActor();
1040 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1043 // TODO: Notify the control to scroll left to the previous page. Should control handle this?
1044 // ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
1052 bool AccessibilityManager::AccessibilityActionPageRight()
1054 Dali::Toolkit::AccessibilityManager handle( this );
1055 if( !mActionPageRightSignal.Empty() )
1057 mActionPageRightSignal.Emit( handle );
1062 if(mIsAccessibilityTtsEnabled)
1064 Actor actor = GetCurrentFocusActor();
1067 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1070 // TODO: Notify the control to scroll right to the next page. Should control handle this?
1071 // ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
1079 bool AccessibilityManager::AccessibilityActionPageUp()
1081 Dali::Toolkit::AccessibilityManager handle( this );
1082 if( !mActionPageUpSignal.Empty() )
1084 mActionPageUpSignal.Emit( handle );
1089 if(mIsAccessibilityTtsEnabled)
1091 Actor actor = GetCurrentFocusActor();
1094 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1097 // TODO: Notify the control to scroll up to the previous page. Should control handle this?
1098 // ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
1106 bool AccessibilityManager::AccessibilityActionPageDown()
1108 Dali::Toolkit::AccessibilityManager handle( this );
1109 if( !mActionPageDownSignal.Empty() )
1111 mActionPageDownSignal.Emit( handle );
1116 if(mIsAccessibilityTtsEnabled)
1118 Actor actor = GetCurrentFocusActor();
1121 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1124 // TODO: Notify the control to scroll down to the next page. Should control handle this?
1125 // ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
1133 bool AccessibilityManager::AccessibilityActionMoveToFirst()
1135 Dali::Toolkit::AccessibilityManager handle( this );
1136 if( !mActionMoveToFirstSignal.Empty() )
1138 mActionMoveToFirstSignal.Emit( handle );
1141 // TODO: Move to the first item on screen
1143 return mIsAccessibilityTtsEnabled;
1146 bool AccessibilityManager::AccessibilityActionMoveToLast()
1148 Dali::Toolkit::AccessibilityManager handle( this );
1149 if( !mActionMoveToLastSignal.Empty() )
1151 mActionMoveToLastSignal.Emit( handle );
1154 // TODO: Move to the last item on screen
1156 return mIsAccessibilityTtsEnabled;
1159 bool AccessibilityManager::AccessibilityActionReadFromTop()
1161 Dali::Toolkit::AccessibilityManager handle( this );
1162 if( !mActionReadFromTopSignal.Empty() )
1164 mActionReadFromTopSignal.Emit( handle );
1167 // TODO: Move to the top item on screen and read from the item continuously
1169 return mIsAccessibilityTtsEnabled;
1172 bool AccessibilityManager::AccessibilityActionReadFromNext()
1174 Dali::Toolkit::AccessibilityManager handle( this );
1176 if( !mActionReadFromNextSignal.Empty() )
1178 mActionReadFromNextSignal.Emit( handle );
1181 if( mIsAccessibilityTtsEnabled )
1183 // Mark that we are in continuous play mode, so TTS signals can move focus.
1184 mContinuousPlayMode = true;
1186 // Attempt to move to the next item and read from the item continuously.
1190 return mIsAccessibilityTtsEnabled;
1193 void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
1195 if( mContinuousPlayMode )
1197 // If we were playing and now we have stopped, attempt to play the next item.
1198 if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
1200 // Attempt to move the focus forward and play.
1201 // If we can't cancel continuous play mode.
1202 if( !MoveFocusForward() )
1204 // We are done, exit continuous play mode.
1205 mContinuousPlayMode = false;
1210 // Unexpected play state change, exit continuous play mode.
1211 mContinuousPlayMode = false;
1216 bool AccessibilityManager::AccessibilityActionZoom()
1218 Dali::Toolkit::AccessibilityManager handle( this );
1219 if( !mActionZoomSignal.Empty() )
1221 mActionZoomSignal.Emit( handle );
1226 if(mIsAccessibilityTtsEnabled)
1228 Actor actor = GetCurrentFocusActor();
1231 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1234 // Notify the control to zoom
1235 ret = GetImplementation( control ).OnAccessibilityZoom();
1243 bool AccessibilityManager::AccessibilityActionReadIndicatorInformation()
1245 Dali::Toolkit::AccessibilityManager handle( this );
1246 if( !mActionReadIndicatorInformationSignal.Empty() )
1248 mActionReadIndicatorInformationSignal.Emit( handle );
1251 // TODO: Read the information in the indicator
1253 return mIsAccessibilityTtsEnabled;
1256 bool AccessibilityManager::AccessibilityActionReadPauseResume()
1258 Dali::Toolkit::AccessibilityManager handle( this );
1259 if( !mActionReadPauseResumeSignal.Empty() )
1261 mActionReadPauseResumeSignal.Emit( handle );
1266 if(mIsAccessibilityTtsEnabled)
1268 // Pause or resume the TTS player
1269 Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
1270 Dali::TtsPlayer::State state = player.GetState();
1271 if(state == Dali::TtsPlayer::PLAYING)
1276 else if(state == Dali::TtsPlayer::PAUSED)
1286 bool AccessibilityManager::AccessibilityActionStartStop()
1288 Dali::Toolkit::AccessibilityManager handle( this );
1289 if( !mActionStartStopSignal.Empty() )
1291 mActionStartStopSignal.Emit( handle );
1294 // TODO: Start/stop the current action
1296 return mIsAccessibilityTtsEnabled;
1299 bool AccessibilityManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
1301 bool handled = false;
1303 // TODO: Need to convert the touchevent for the focused actor?
1305 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
1308 handled = GetImplementation( control ).OnAccessibilityTouch(touchEvent);
1314 bool AccessibilityManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
1316 bool handled = false;
1318 if( panEvent.state == Gesture::Started )
1320 // Find the focusable actor at the event position
1321 Dali::HitTestAlgorithm::Results results;
1322 AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
1324 Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
1325 mCurrentGesturedActor = results.actor;
1327 if(!mCurrentGesturedActor)
1329 DALI_LOG_ERROR("Gesture detected, but no hit actor\n");
1333 // Gesture::Finished (Up) events are delivered with previous (Motion) event position
1334 // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
1335 if ( Gesture::Finished != panEvent.state )
1337 // Store the previous position for next Gesture::Finished iteration.
1338 mPreviousPosition = panEvent.previousPosition;
1341 Actor rootActor = Stage::GetCurrent().GetRootLayer();
1343 Dali::PanGesture pan(panEvent.state);
1344 pan.time = panEvent.time;
1345 pan.numberOfTouches = panEvent.numberOfTouches;
1346 pan.screenPosition = panEvent.currentPosition;
1347 pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
1348 pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
1349 pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
1351 // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
1352 while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
1354 Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
1357 Vector2 localCurrent;
1358 control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
1359 pan.position = localCurrent;
1361 Vector2 localPrevious;
1362 control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
1364 pan.displacement = localCurrent - localPrevious;
1365 pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
1366 pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
1368 handled = GetImplementation( control ).OnAccessibilityPan(pan);
1371 // If the gesture is not handled by the control, check its parent
1374 mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
1376 if(!mCurrentGesturedActor)
1378 DALI_LOG_ERROR("no more gestured actor\n");
1383 // If handled, then update the pan gesture properties
1384 PanGestureDetector::SetPanGestureProperties( pan );
1391 Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
1393 return mFocusChangedSignal;
1396 Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
1398 return mFocusOvershotSignal;
1401 Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
1403 return mFocusedActorActivatedSignal;
1406 } // namespace Internal
1408 } // namespace Toolkit