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