Updates for const->constexpr
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / accessibility-manager / accessibility-manager-impl.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include "accessibility-manager-impl.h"
20
21 // EXTERNAL INCLUDES
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/integration-api/debug.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/devel-api/asset-manager/asset-manager.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>
35
36 namespace Dali
37 {
38
39 namespace Toolkit
40 {
41
42 namespace Internal
43 {
44
45 namespace // unnamed namespace
46 {
47
48 // Signals
49
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";
53
54 #if defined(DEBUG_ENABLED)
55 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
56 #endif
57
58 const char* const ACTOR_FOCUSABLE("focusable");
59 const char* const IS_FOCUS_GROUP("isFocusGroup");
60
61 const char* FOCUS_BORDER_IMAGE_FILE_NAME = "B16-8_TTS_focus.9.png";
62
63 const char* FOCUS_SOUND_FILE_NAME = "Focus.ogg";
64 const char* FOCUS_CHAIN_END_SOUND_FILE_NAME = "End_of_List.ogg";
65
66 /**
67  * The function to be used in the hit-test algorithm to check whether the actor is hittable.
68  */
69 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
70 {
71   bool hittable = false;
72
73   switch (type)
74   {
75     case Dali::HitTestAlgorithm::CHECK_ACTOR:
76     {
77       // Check whether the actor is visible and not fully transparent.
78       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE )
79        && actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f) // not FULLY_TRANSPARENT
80       {
81         // Check whether the actor is focusable
82         Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
83         if(propertyActorFocusable != Property::INVALID_INDEX)
84         {
85           hittable = actor.GetProperty<bool>(propertyActorFocusable);
86         }
87       }
88       break;
89     }
90     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
91     {
92       if( actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE ) ) // Actor is visible, if not visible then none of its children are visible.
93       {
94         hittable = true;
95       }
96       break;
97     }
98     default:
99     {
100       break;
101     }
102   }
103
104   return hittable;
105 };
106
107 }
108
109 AccessibilityManager::AccessibilityManager()
110 : mCurrentFocusActor(FocusIDPair(0, 0)),
111   mCurrentGesturedActor(),
112   mFocusIndicatorActor(),
113   mPreviousPosition( 0.0f, 0.0f ),
114   mRecursiveFocusMoveCounter(0),
115   mFocusSoundFilePath(),
116   mFocusChainEndSoundFilePath(),
117   mIsWrapped(false),
118   mIsFocusWithinGroup(false),
119   mIsEndcapFeedbackEnabled(false),
120   mIsEndcapFeedbackPlayed(false),
121   mIsAccessibilityTtsEnabled(false),
122   mTtsCreated(false),
123   mIsFocusIndicatorEnabled(false),
124   mContinuousPlayMode(false),
125   mIsFocusSoundFilePathSet(false),
126   mIsFocusChainEndSoundFilePathSet(false)
127 {
128 }
129
130 AccessibilityManager::~AccessibilityManager()
131 {
132 }
133
134 void AccessibilityManager::Initialise()
135 {
136   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
137   adaptor.SetActionHandler(*this);
138   adaptor.SetGestureHandler(*this);
139
140   ChangeAccessibilityStatus();
141 }
142
143 AccessibilityManager::ActorAdditionalInfo AccessibilityManager::GetActorAdditionalInfo(const unsigned int actorID) const
144 {
145   ActorAdditionalInfo data;
146   IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
147   if(iter != mIDAdditionalInfoContainer.end())
148   {
149     data = (*iter).second;
150   }
151
152   return data;
153 }
154
155 void AccessibilityManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
156 {
157   ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
158   actorInfo.mFocusOrder = order;
159   mIDAdditionalInfoContainer.erase(actorID);
160   mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
161 }
162
163 void AccessibilityManager::SetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type, const std::string& text)
164 {
165   if(actor)
166   {
167     unsigned int actorID = actor.GetProperty< int >( Actor::Property::ID );
168
169     ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
170     info.mAccessibilityAttributes[type] = text;
171
172     mIDAdditionalInfoContainer.erase(actorID);
173     mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
174   }
175 }
176
177 std::string AccessibilityManager::GetAccessibilityAttribute(Actor actor, Toolkit::AccessibilityManager::AccessibilityAttribute type) const
178 {
179   std::string text;
180
181   if(actor)
182   {
183     ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID ));
184     text = data.mAccessibilityAttributes[type];
185   }
186
187   return text;
188 }
189
190 void AccessibilityManager::SetFocusOrder(Actor actor, const unsigned int order)
191 {
192   // Do nothing if the focus order of the actor is not changed.
193   if(actor && GetFocusOrder(actor) != order)
194   {
195     // Firstly delete the actor from the focus chain if it's already there with a different focus order.
196     mFocusIDContainer.erase(GetFocusOrder(actor));
197
198     // Create/retrieve actor focusable property
199     Property::Index propertyActorFocusable = actor.RegisterProperty( ACTOR_FOCUSABLE, true, Property::READ_WRITE );
200
201     if(order == 0)
202     {
203       // The actor is not focusable without a defined focus order.
204       actor.SetProperty(propertyActorFocusable, false);
205
206       // If the actor is currently being focused, it should clear the focus
207       if(actor == GetCurrentFocusActor())
208       {
209         ClearFocus();
210       }
211     }
212     else // Insert the actor to the focus chain
213     {
214       // Check whether there is another actor in the focus chain with the same focus order already.
215       FocusIDIter focusIDIter = mFocusIDContainer.find(order);
216       if(focusIDIter != mFocusIDContainer.end())
217       {
218         // We need to increase the focus order of that actor and all the actors followed it
219         // in the focus chain.
220         FocusIDIter lastIter = mFocusIDContainer.end();
221         --lastIter;//We want forward iterator to the last element here
222         mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
223
224         // Update the actor's focus order in its additional data
225         SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
226
227         for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
228         {
229           FocusIDIter previousIter = iter;
230           --previousIter;//We want forward iterator to the previous element here
231           unsigned int actorID = (*previousIter).second;
232           (*iter).second = actorID;
233
234           // Update the actor's focus order in its additional data
235           SynchronizeActorAdditionalInfo(actorID, (*iter).first);
236         }
237
238         mFocusIDContainer.erase(order);
239       }
240
241       // The actor is focusable
242       actor.SetProperty(propertyActorFocusable, true);
243
244       // Now we insert the actor into the focus chain with the specified focus order
245       mFocusIDContainer.insert(FocusIDPair(order, actor.GetProperty< int >( Actor::Property::ID )));
246     }
247
248     // Update the actor's focus order in its additional data
249     SynchronizeActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID ), order);
250   }
251 }
252
253 unsigned int AccessibilityManager::GetFocusOrder(Actor actor) const
254 {
255   unsigned int focusOrder = 0;
256
257   if(actor)
258   {
259     ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetProperty< int >( Actor::Property::ID ));
260     focusOrder = data.mFocusOrder;
261   }
262
263   return focusOrder;
264 }
265
266 unsigned int AccessibilityManager::GenerateNewFocusOrder() const
267 {
268   unsigned int order = 1;
269   FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
270
271   if(iter != mFocusIDContainer.rend())
272   {
273     order = (*iter).first + 1;
274   }
275
276   return order;
277 }
278
279 Actor AccessibilityManager::GetActorByFocusOrder(const unsigned int order)
280 {
281   Actor actor = Actor();
282
283   FocusIDIter focusIDIter = mFocusIDContainer.find(order);
284   if(focusIDIter != mFocusIDContainer.end())
285   {
286     Actor rootActor = Stage::GetCurrent().GetRootLayer();
287     actor = rootActor.FindChildById(mFocusIDContainer[order]);
288   }
289
290   return actor;
291 }
292
293 bool AccessibilityManager::SetCurrentFocusActor(Actor actor)
294 {
295   if(actor)
296   {
297     return DoSetCurrentFocusActor(actor.GetProperty< int >( Actor::Property::ID ));
298   }
299
300   return false;
301 }
302
303 bool AccessibilityManager::DoSetCurrentFocusActor(const unsigned int actorID)
304 {
305   Actor rootActor = Stage::GetCurrent().GetRootLayer();
306
307   // If the group mode is enabled, check which focus group the current focused actor belongs to
308   Actor focusGroup;
309   if(mIsFocusWithinGroup)
310   {
311     focusGroup = GetFocusGroup(GetCurrentFocusActor());
312   }
313
314   if(!focusGroup)
315   {
316     focusGroup = rootActor;
317   }
318
319   Actor actor = focusGroup.FindChildById(actorID);
320
321   // Check whether the actor is in the stage
322   if(actor)
323   {
324     // Check whether the actor is focusable
325     bool actorFocusable = false;
326     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
327     if(propertyActorFocusable != Property::INVALID_INDEX)
328     {
329       actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
330     }
331
332     // Go through the actor's hierarchy to check whether the actor is visible
333     bool actorVisible = actor.GetCurrentProperty< bool >( Actor::Property::VISIBLE );
334     Actor parent = actor.GetParent();
335     while (actorVisible && parent && parent != rootActor)
336     {
337       actorVisible = parent.GetCurrentProperty< bool >( Actor::Property::VISIBLE );
338       parent = parent.GetParent();
339     }
340
341     // Check whether the actor is fully transparent
342     bool actorOpaque = actor.GetCurrentProperty< Vector4 >( Actor::Property::WORLD_COLOR ).a > 0.01f;
343
344     // Set the focus only when the actor is focusable and visible and not fully transparent
345     if(actorVisible && actorFocusable && actorOpaque)
346     {
347       // Draw the focus indicator upon the focused actor
348       if( mIsFocusIndicatorEnabled )
349       {
350         actor.Add( GetFocusIndicatorActor() );
351       }
352
353       // Send notification for the change of focus actor
354       mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
355
356       // Save the current focused actor
357       mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
358
359       if(mIsAccessibilityTtsEnabled)
360       {
361         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
362         if(soundPlayer)
363         {
364           if (!mIsFocusSoundFilePathSet)
365           {
366             const std::string soundDirPath = AssetManager::GetDaliSoundPath();
367             mFocusSoundFilePath = soundDirPath + FOCUS_SOUND_FILE_NAME;
368             mIsFocusSoundFilePathSet = true;
369           }
370           soundPlayer.PlaySound(mFocusSoundFilePath);
371         }
372
373         // Play the accessibility attributes with the TTS player.
374         Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
375
376         // Combine attribute texts to one text
377         std::string informationText;
378         for(int i = 0; i < Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
379         {
380           if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
381           {
382             if( i > 0 )
383             {
384               informationText += ", "; // for space time between each information
385             }
386             informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
387           }
388         }
389         player.Play(informationText);
390       }
391
392       return true;
393     }
394   }
395
396   DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
397   return false;
398 }
399
400 Actor AccessibilityManager::GetCurrentFocusActor()
401 {
402   Actor rootActor = Stage::GetCurrent().GetRootLayer();
403   return rootActor.FindChildById(mCurrentFocusActor.second);
404 }
405
406 Actor AccessibilityManager::GetCurrentFocusGroup()
407 {
408   return GetFocusGroup(GetCurrentFocusActor());
409 }
410
411 unsigned int AccessibilityManager::GetCurrentFocusOrder()
412 {
413   return mCurrentFocusActor.first;
414 }
415
416 bool AccessibilityManager::MoveFocusForward()
417 {
418   bool ret = false;
419   mRecursiveFocusMoveCounter = 0;
420
421   FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
422   if(focusIDIter != mFocusIDContainer.end())
423   {
424     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
425     ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
426   }
427   else
428   {
429     // TODO: if there is not focused actor, move first actor
430     if(!mFocusIDContainer.empty())
431     {
432       //if there is not focused actor, move 1st actor
433       focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
434       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
435       ret = DoSetCurrentFocusActor((*focusIDIter).second);
436     }
437   }
438
439   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
440
441   return ret;
442 }
443
444 bool AccessibilityManager::MoveFocusBackward()
445 {
446   bool ret = false;
447   mRecursiveFocusMoveCounter = 0;
448
449   FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
450   if(focusIDIter != mFocusIDContainer.end())
451   {
452     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
453     ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
454   }
455   else
456   {
457     // TODO: if there is not focused actor, move last actor
458     if(!mFocusIDContainer.empty())
459     {
460       //if there is not focused actor, move last actor
461       focusIDIter = mFocusIDContainer.end();
462       --focusIDIter;//We want forward iterator to the last element here
463       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
464       ret = DoSetCurrentFocusActor((*focusIDIter).second);
465     }
466   }
467
468   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
469
470   return ret;
471 }
472
473 void AccessibilityManager::DoActivate(Actor actor)
474 {
475   if(actor)
476   {
477     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
478     if(control)
479     {
480       // Notify the control that it is activated
481       GetImplementation( control ).AccessibilityActivate();
482     }
483
484     // Send notification for the activation of focused actor
485     mFocusedActorActivatedSignal.Emit(actor);
486   }
487 }
488
489 void AccessibilityManager::ClearFocus()
490 {
491   Actor actor = GetCurrentFocusActor();
492   if( actor && mFocusIndicatorActor )
493   {
494     actor.Remove( mFocusIndicatorActor );
495   }
496
497   mCurrentFocusActor = FocusIDPair(0, 0);
498
499   // Send notification for the change of focus actor
500   mFocusChangedSignal.Emit(actor, Actor());
501
502   if(mIsAccessibilityTtsEnabled)
503   {
504     // Stop the TTS playing if any
505     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
506     player.Stop();
507   }
508 }
509
510 void AccessibilityManager::Reset()
511 {
512   ClearFocus();
513   mFocusIDContainer.clear();
514   mIDAdditionalInfoContainer.clear();
515 }
516
517 void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup)
518 {
519   if(actor)
520   {
521     // Create/Set focus group property.
522     actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
523   }
524 }
525
526 bool AccessibilityManager::IsFocusGroup(Actor actor) const
527 {
528   // Check whether the actor is a focus group
529   bool isFocusGroup = false;
530
531   if(actor)
532   {
533     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
534     if(propertyIsFocusGroup != Property::INVALID_INDEX)
535     {
536       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
537     }
538   }
539
540   return isFocusGroup;
541 }
542
543 Actor AccessibilityManager::GetFocusGroup(Actor actor)
544 {
545   // Go through the actor's hierarchy to check which focus group the actor belongs to
546   while (actor && !IsFocusGroup(actor))
547   {
548     actor = actor.GetParent();
549   }
550
551   return actor;
552 }
553
554 Vector2 AccessibilityManager::GetReadPosition() const
555 {
556   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
557   return adaptor.GetReadPosition();
558 }
559
560 void AccessibilityManager::SetGroupMode(bool enabled)
561 {
562   mIsFocusWithinGroup = enabled;
563 }
564
565 bool AccessibilityManager::GetGroupMode() const
566 {
567   return mIsFocusWithinGroup;
568 }
569
570 void AccessibilityManager::SetWrapMode(bool wrapped)
571 {
572   mIsWrapped = wrapped;
573 }
574
575 bool AccessibilityManager::GetWrapMode() const
576 {
577   return mIsWrapped;
578 }
579
580 void AccessibilityManager::SetFocusIndicatorActor(Actor indicator)
581 {
582   if( mFocusIndicatorActor != indicator )
583   {
584     Actor currentFocusActor = GetCurrentFocusActor();
585     if( currentFocusActor )
586     {
587       // The new focus indicator should be added to the current focused actor immediately
588       if( mFocusIndicatorActor )
589       {
590         currentFocusActor.Remove( mFocusIndicatorActor );
591       }
592
593       if( indicator )
594       {
595         currentFocusActor.Add( indicator );
596       }
597     }
598
599     mFocusIndicatorActor = indicator;
600   }
601 }
602
603 Actor AccessibilityManager::GetFocusIndicatorActor()
604 {
605   if( ! mFocusIndicatorActor )
606   {
607     // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
608     const std::string imageDirPath = AssetManager::GetDaliImagePath();
609     const std::string focusBorderImagePath = imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME;
610
611     mFocusIndicatorActor = Toolkit::ImageView::New(focusBorderImagePath);
612     mFocusIndicatorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
613     mFocusIndicatorActor.SetProperty( Actor::Property::POSITION_Z,  1.0f );
614
615     // Apply size constraint to the focus indicator
616     mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
617   }
618
619   return mFocusIndicatorActor;
620 }
621
622 bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
623 {
624   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
625   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
626
627   if( (forward && ++focusIDIter == mFocusIDContainer.end())
628     || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
629   {
630     if(mIsEndcapFeedbackEnabled)
631     {
632       if(mIsEndcapFeedbackPlayed == false)
633       {
634         // play sound & skip moving once
635         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
636         if(soundPlayer)
637         {
638           if (!mIsFocusChainEndSoundFilePathSet)
639           {
640             const std::string soundDirPath = AssetManager::GetDaliSoundPath();
641             mFocusChainEndSoundFilePath = soundDirPath + FOCUS_CHAIN_END_SOUND_FILE_NAME;
642             mIsFocusChainEndSoundFilePathSet = true;
643           }
644           soundPlayer.PlaySound(mFocusChainEndSoundFilePath);
645         }
646
647         mIsEndcapFeedbackPlayed = true;
648         return true;
649       }
650       mIsEndcapFeedbackPlayed = false;
651     }
652
653     if(wrapped)
654     {
655       if(forward)
656       {
657         focusIDIter = mFocusIDContainer.begin();
658       }
659       else
660       {
661         focusIDIter = mFocusIDContainer.end();
662         --focusIDIter;//We want forward iterator to the last element here
663       }
664     }
665     else
666     {
667       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
668       // Send notification for handling overshooted situation
669       mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS);
670
671       return false; // Try to move the focus out of the scope
672     }
673   }
674
675   // Invalid focus.
676   if( focusIDIter == mFocusIDContainer.end() )
677   {
678     return false;
679   }
680
681   // Note: This function performs the focus change.
682   if( !DoSetCurrentFocusActor( (*focusIDIter).second ) )
683   {
684     mRecursiveFocusMoveCounter++;
685     if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
686     {
687       // We've attempted to focus all the actors in the whole focus chain and no actor
688       // can be focused successfully.
689       DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
690
691       return false;
692     }
693     else
694     {
695       return DoMoveFocus(focusIDIter, forward, wrapped);
696     }
697   }
698
699   return true;
700 }
701
702 void AccessibilityManager::SetFocusable(Actor actor, bool focusable)
703 {
704   if(actor)
705   {
706     // Create/Set actor focusable property.
707     actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
708   }
709 }
710
711 bool AccessibilityManager::ChangeAccessibilityStatus()
712 {
713   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
714   mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
715   Dali::Toolkit::AccessibilityManager handle( this );
716
717   if(mIsAccessibilityTtsEnabled)
718   {
719     // Show indicator when tts turned on if there is focused actor.
720     Actor actor = GetCurrentFocusActor();
721     if(actor)
722     {
723       actor.Add( GetFocusIndicatorActor() );
724     }
725     mIsFocusIndicatorEnabled = true;
726
727     // Connect a signal to the TTS player to implement continuous reading mode.
728     Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
729     player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
730     mTtsCreated = true;
731   }
732   else
733   {
734     // Hide indicator when tts turned off
735     Actor actor = GetCurrentFocusActor();
736     if( actor && mFocusIndicatorActor )
737     {
738       actor.Remove( mFocusIndicatorActor );
739     }
740     mIsFocusIndicatorEnabled = false;
741
742     if( mTtsCreated )
743     {
744       // Disconnect the TTS state change signal.
745       Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
746       player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
747       mTtsCreated = true;
748     }
749   }
750
751   mStatusChangedSignal.Emit( handle );
752
753   return true;
754 }
755
756 bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
757 {
758   Dali::Toolkit::AccessibilityManager handle( this );
759   if( !mActionNextSignal.Empty() )
760   {
761     mActionNextSignal.Emit( handle );
762   }
763
764   if(mIsAccessibilityTtsEnabled)
765   {
766     mIsEndcapFeedbackEnabled = allowEndFeedback;
767     return MoveFocusForward();
768   }
769   else
770   {
771     return false;
772   }
773 }
774
775 bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
776 {
777   Dali::Toolkit::AccessibilityManager handle( this );
778   if( !mActionPreviousSignal.Empty() )
779   {
780     mActionPreviousSignal.Emit( handle );
781   }
782
783   if(mIsAccessibilityTtsEnabled)
784   {
785     mIsEndcapFeedbackEnabled = allowEndFeedback;
786     return MoveFocusBackward();
787   }
788   else
789   {
790     return false;
791   }
792 }
793
794 bool AccessibilityManager::AccessibilityActionActivate()
795 {
796   Dali::Toolkit::AccessibilityManager handle( this );
797   if( !mActionActivateSignal.Empty() )
798   {
799     mActionActivateSignal.Emit( handle );
800   }
801
802   bool ret = false;
803
804   Actor actor = GetCurrentFocusActor();
805   if(actor)
806   {
807     DoActivate(actor);
808     ret = true;
809   }
810
811   return ret;
812 }
813
814 bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
815 {
816   Dali::Toolkit::AccessibilityManager handle( this );
817
818   if( allowReadAgain )
819   {
820     if ( !mActionReadSignal.Empty() )
821     {
822       mActionReadSignal.Emit( handle );
823     }
824   }
825   else
826   {
827     if ( !mActionOverSignal.Empty() )
828     {
829       mActionOverSignal.Emit( handle );
830     }
831   }
832
833   bool ret = false;
834
835   if(mIsAccessibilityTtsEnabled)
836   {
837     // Find the focusable actor at the read position
838     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
839     Dali::HitTestAlgorithm::Results results;
840     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
841
842     FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
843     if(focusIDIter != mFocusIDContainer.end())
844     {
845       if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
846       {
847         // Move the focus to the actor
848         ret = SetCurrentFocusActor(results.actor);
849         DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
850       }
851     }
852   }
853
854   return ret;
855 }
856
857 bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
858 {
859   Dali::Toolkit::AccessibilityManager handle( this );
860   if( !mActionReadNextSignal.Empty() )
861   {
862     mActionReadNextSignal.Emit( handle );
863   }
864
865   if(mIsAccessibilityTtsEnabled)
866   {
867     return MoveFocusForward();
868   }
869   else
870   {
871     return false;
872   }
873 }
874
875 bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
876 {
877   Dali::Toolkit::AccessibilityManager handle( this );
878   if( !mActionReadPreviousSignal.Empty() )
879   {
880     mActionReadPreviousSignal.Emit( handle );
881   }
882
883   if(mIsAccessibilityTtsEnabled)
884   {
885     return MoveFocusBackward();
886   }
887   else
888   {
889     return false;
890   }
891 }
892
893 bool AccessibilityManager::AccessibilityActionUp()
894 {
895   Dali::Toolkit::AccessibilityManager handle( this );
896   if( !mActionUpSignal.Empty() )
897   {
898     mActionUpSignal.Emit( handle );
899   }
900
901   bool ret = false;
902
903   if(mIsAccessibilityTtsEnabled)
904   {
905     Actor actor = GetCurrentFocusActor();
906     if(actor)
907     {
908       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
909       if(control)
910       {
911         // Notify the control that it is activated
912         ret = GetImplementation( control ).OnAccessibilityValueChange(true);
913       }
914     }
915   }
916
917   return ret;
918 }
919
920 bool AccessibilityManager::AccessibilityActionDown()
921 {
922   Dali::Toolkit::AccessibilityManager handle( this );
923   if( !mActionDownSignal.Empty() )
924   {
925     mActionDownSignal.Emit( handle );
926   }
927
928   bool ret = false;
929
930   if(mIsAccessibilityTtsEnabled)
931   {
932     Actor actor = GetCurrentFocusActor();
933     if(actor)
934     {
935       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
936       if(control)
937       {
938         // Notify the control that it is activated
939         ret = GetImplementation( control ).OnAccessibilityValueChange(false);
940       }
941     }
942   }
943
944   return ret;
945 }
946
947 bool AccessibilityManager::ClearAccessibilityFocus()
948 {
949   Dali::Toolkit::AccessibilityManager handle( this );
950   if( !mActionClearFocusSignal.Empty() )
951   {
952     mActionClearFocusSignal.Emit( handle );
953   }
954
955   if(mIsAccessibilityTtsEnabled)
956   {
957     ClearFocus();
958     return true;
959   }
960   else
961   {
962     return false;
963   }
964 }
965
966 bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touch )
967 {
968   Dali::Toolkit::AccessibilityManager handle( this );
969   if( !mActionScrollSignal.Empty() )
970   {
971     mActionScrollSignal.Emit( handle, touch );
972   }
973
974   return true;
975 }
976
977 bool AccessibilityManager::AccessibilityActionBack()
978 {
979   Dali::Toolkit::AccessibilityManager handle( this );
980   if( !mActionBackSignal.Empty() )
981   {
982     mActionBackSignal.Emit( handle );
983   }
984
985   // TODO: Back to previous view
986
987   return mIsAccessibilityTtsEnabled;
988 }
989
990 bool AccessibilityManager::AccessibilityActionScrollUp()
991 {
992   Dali::Toolkit::AccessibilityManager handle( this );
993   if( !mActionScrollUpSignal.Empty() )
994   {
995     mActionScrollUpSignal.Emit( handle );
996   }
997
998   bool ret = false;
999
1000   if(mIsAccessibilityTtsEnabled)
1001   {
1002     Actor actor = GetCurrentFocusActor();
1003     if(actor)
1004     {
1005       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1006       if(control)
1007       {
1008         // TODO: Notify the control to scroll up. Should control handle this?
1009 //        ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
1010       }
1011     }
1012   }
1013
1014   return ret;
1015 }
1016
1017 bool AccessibilityManager::AccessibilityActionScrollDown()
1018 {
1019   Dali::Toolkit::AccessibilityManager handle( this );
1020   if( !mActionScrollDownSignal.Empty() )
1021   {
1022     mActionScrollDownSignal.Emit( handle );
1023   }
1024
1025   bool ret = false;
1026
1027   if(mIsAccessibilityTtsEnabled)
1028   {
1029     Actor actor = GetCurrentFocusActor();
1030     if(actor)
1031     {
1032       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1033       if(control)
1034       {
1035         // TODO: Notify the control to scroll down. Should control handle this?
1036 //        ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
1037       }
1038     }
1039   }
1040
1041   return ret;
1042 }
1043
1044 bool AccessibilityManager::AccessibilityActionPageLeft()
1045 {
1046   Dali::Toolkit::AccessibilityManager handle( this );
1047   if( !mActionPageLeftSignal.Empty() )
1048   {
1049     mActionPageLeftSignal.Emit( handle );
1050   }
1051
1052   bool ret = false;
1053
1054   if(mIsAccessibilityTtsEnabled)
1055   {
1056     Actor actor = GetCurrentFocusActor();
1057     if(actor)
1058     {
1059       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1060       if(control)
1061       {
1062         // TODO: Notify the control to scroll left to the previous page. Should control handle this?
1063 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
1064       }
1065     }
1066   }
1067
1068   return ret;
1069 }
1070
1071 bool AccessibilityManager::AccessibilityActionPageRight()
1072 {
1073   Dali::Toolkit::AccessibilityManager handle( this );
1074   if( !mActionPageRightSignal.Empty() )
1075   {
1076     mActionPageRightSignal.Emit( handle );
1077   }
1078
1079   bool ret = false;
1080
1081   if(mIsAccessibilityTtsEnabled)
1082   {
1083     Actor actor = GetCurrentFocusActor();
1084     if(actor)
1085     {
1086       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1087       if(control)
1088       {
1089         // TODO: Notify the control to scroll right to the next page. Should control handle this?
1090 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
1091       }
1092     }
1093   }
1094
1095   return ret;
1096 }
1097
1098 bool AccessibilityManager::AccessibilityActionPageUp()
1099 {
1100   Dali::Toolkit::AccessibilityManager handle( this );
1101   if( !mActionPageUpSignal.Empty() )
1102   {
1103     mActionPageUpSignal.Emit( handle );
1104   }
1105
1106   bool ret = false;
1107
1108   if(mIsAccessibilityTtsEnabled)
1109   {
1110     Actor actor = GetCurrentFocusActor();
1111     if(actor)
1112     {
1113       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1114       if(control)
1115       {
1116         // TODO: Notify the control to scroll up to the previous page. Should control handle this?
1117 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
1118       }
1119     }
1120   }
1121
1122   return ret;
1123 }
1124
1125 bool AccessibilityManager::AccessibilityActionPageDown()
1126 {
1127   Dali::Toolkit::AccessibilityManager handle( this );
1128   if( !mActionPageDownSignal.Empty() )
1129   {
1130     mActionPageDownSignal.Emit( handle );
1131   }
1132
1133   bool ret = false;
1134
1135   if(mIsAccessibilityTtsEnabled)
1136   {
1137     Actor actor = GetCurrentFocusActor();
1138     if(actor)
1139     {
1140       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1141       if(control)
1142       {
1143         // TODO: Notify the control to scroll down to the next page. Should control handle this?
1144 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
1145       }
1146     }
1147   }
1148
1149   return ret;
1150 }
1151
1152 bool AccessibilityManager::AccessibilityActionMoveToFirst()
1153 {
1154   Dali::Toolkit::AccessibilityManager handle( this );
1155   if( !mActionMoveToFirstSignal.Empty() )
1156   {
1157     mActionMoveToFirstSignal.Emit( handle );
1158   }
1159
1160   // TODO: Move to the first item on screen
1161
1162   return mIsAccessibilityTtsEnabled;
1163 }
1164
1165 bool AccessibilityManager::AccessibilityActionMoveToLast()
1166 {
1167   Dali::Toolkit::AccessibilityManager handle( this );
1168   if( !mActionMoveToLastSignal.Empty() )
1169   {
1170     mActionMoveToLastSignal.Emit( handle );
1171   }
1172
1173   // TODO: Move to the last item on screen
1174
1175   return mIsAccessibilityTtsEnabled;
1176 }
1177
1178 bool AccessibilityManager::AccessibilityActionReadFromTop()
1179 {
1180   Dali::Toolkit::AccessibilityManager handle( this );
1181   if( !mActionReadFromTopSignal.Empty() )
1182   {
1183     mActionReadFromTopSignal.Emit( handle );
1184   }
1185
1186   // TODO: Move to the top item on screen and read from the item continuously
1187
1188   return mIsAccessibilityTtsEnabled;
1189 }
1190
1191 bool AccessibilityManager::AccessibilityActionReadFromNext()
1192 {
1193   Dali::Toolkit::AccessibilityManager handle( this );
1194
1195   if( !mActionReadFromNextSignal.Empty() )
1196   {
1197     mActionReadFromNextSignal.Emit( handle );
1198   }
1199
1200   if( mIsAccessibilityTtsEnabled )
1201   {
1202     // Mark that we are in continuous play mode, so TTS signals can move focus.
1203     mContinuousPlayMode = true;
1204
1205     // Attempt to move to the next item and read from the item continuously.
1206     MoveFocusForward();
1207   }
1208
1209   return mIsAccessibilityTtsEnabled;
1210 }
1211
1212 void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
1213 {
1214   if( mContinuousPlayMode )
1215   {
1216     // If we were playing and now we have stopped, attempt to play the next item.
1217     if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
1218     {
1219       // Attempt to move the focus forward and play.
1220       // If we can't cancel continuous play mode.
1221       if( !MoveFocusForward() )
1222       {
1223         // We are done, exit continuous play mode.
1224         mContinuousPlayMode = false;
1225       }
1226     }
1227     else
1228     {
1229       // Unexpected play state change, exit continuous play mode.
1230       mContinuousPlayMode = false;
1231     }
1232   }
1233 }
1234
1235 bool AccessibilityManager::AccessibilityActionZoom()
1236 {
1237   Dali::Toolkit::AccessibilityManager handle( this );
1238   if( !mActionZoomSignal.Empty() )
1239   {
1240     mActionZoomSignal.Emit( handle );
1241   }
1242
1243   bool ret = false;
1244
1245   if(mIsAccessibilityTtsEnabled)
1246   {
1247     Actor actor = GetCurrentFocusActor();
1248     if(actor)
1249     {
1250       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1251       if(control)
1252       {
1253         // Notify the control to zoom
1254         ret = GetImplementation( control ).OnAccessibilityZoom();
1255       }
1256     }
1257   }
1258
1259   return ret;
1260 }
1261
1262 bool AccessibilityManager::AccessibilityActionReadPauseResume()
1263 {
1264   Dali::Toolkit::AccessibilityManager handle( this );
1265   if( !mActionReadPauseResumeSignal.Empty() )
1266   {
1267     mActionReadPauseResumeSignal.Emit( handle );
1268   }
1269
1270   bool ret = false;
1271
1272   if(mIsAccessibilityTtsEnabled)
1273   {
1274     // Pause or resume the TTS player
1275     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
1276     Dali::TtsPlayer::State state = player.GetState();
1277     if(state == Dali::TtsPlayer::PLAYING)
1278     {
1279       player.Pause();
1280       ret = true;
1281     }
1282     else if(state == Dali::TtsPlayer::PAUSED)
1283     {
1284       player.Resume();
1285       ret = true;
1286     }
1287   }
1288
1289   return ret;
1290 }
1291
1292 bool AccessibilityManager::AccessibilityActionStartStop()
1293 {
1294   Dali::Toolkit::AccessibilityManager handle( this );
1295   if( !mActionStartStopSignal.Empty() )
1296   {
1297     mActionStartStopSignal.Emit( handle );
1298   }
1299
1300   // TODO: Start/stop the current action
1301
1302   return mIsAccessibilityTtsEnabled;
1303 }
1304
1305 bool AccessibilityManager::HandlePanGesture(const AccessibilityGestureEvent& panEvent)
1306 {
1307   bool handled = false;
1308
1309   if( panEvent.state == AccessibilityGestureEvent::Started )
1310   {
1311     // Find the focusable actor at the event position
1312     Dali::HitTestAlgorithm::Results results;
1313     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
1314
1315     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
1316     mCurrentGesturedActor = results.actor;
1317
1318     if(!mCurrentGesturedActor)
1319     {
1320       DALI_LOG_ERROR("Gesture detected, but no hit actor\n");
1321     }
1322   }
1323
1324   // Gesture::Finished (Up) events are delivered with previous (Motion) event position
1325   // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
1326   if ( AccessibilityGestureEvent::Finished != panEvent.state )
1327   {
1328     // Store the previous position for next Gesture::Finished iteration.
1329     mPreviousPosition = panEvent.previousPosition;
1330   }
1331
1332   Actor rootActor = Stage::GetCurrent().GetRootLayer();
1333
1334   Dali::PanGesture pan( static_cast<Dali::Gesture::State>(panEvent.state) );
1335
1336   pan.time = panEvent.time;
1337   pan.numberOfTouches = panEvent.numberOfTouches;
1338   pan.screenPosition = panEvent.currentPosition;
1339   pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
1340   pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
1341   pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
1342
1343   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
1344   while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
1345   {
1346     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
1347     if(control)
1348     {
1349       Vector2 localCurrent;
1350       control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
1351       pan.position = localCurrent;
1352
1353       Vector2 localPrevious;
1354       control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
1355
1356       pan.displacement = localCurrent - localPrevious;
1357       pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
1358       pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
1359
1360       handled = GetImplementation( control ).OnAccessibilityPan(pan);
1361     }
1362
1363     // If the gesture is not handled by the control, check its parent
1364     if(!handled)
1365     {
1366       mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
1367
1368       if(!mCurrentGesturedActor)
1369       {
1370         DALI_LOG_ERROR("no more gestured actor\n");
1371       }
1372     }
1373     else
1374     {
1375       // If handled, then update the pan gesture properties
1376       PanGestureDetector::SetPanGestureProperties( pan );
1377     }
1378   }
1379
1380   return handled;
1381 }
1382
1383 Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
1384 {
1385   return mFocusChangedSignal;
1386 }
1387
1388 Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
1389 {
1390   return mFocusOvershotSignal;
1391 }
1392
1393 Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
1394 {
1395   return mFocusedActorActivatedSignal;
1396 }
1397
1398 } // namespace Internal
1399
1400 } // namespace Toolkit
1401
1402 } // namespace Dali