[Tizen] Be a bit smarter with SetFocusedActorPosition
[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       auto adaptor = AccessibilityAdaptor::Get();
364       Vector2 readPosition = adaptor.GetReadPosition();
365       auto actorPosition = actor.GetCurrentProperty<Vector2>(Actor::Property::SCREEN_POSITION);
366       auto actorSize = actor.GetCurrentProperty<Vector2>(Actor::Property::SIZE);
367       Rect<> actorRect(actorPosition.x, actorPosition.y, actorSize.width, actorSize.height);
368
369       if(actorRect.Contains(Rect<>(readPosition.x, readPosition.y, 0, 0)))
370       {
371         // If the last touched position is within the extents of the actor,
372         // then use that position. (The center may be covered by some other actor).
373         adaptor.SetFocusedActorPosition(readPosition);
374       }
375       else
376       {
377         // Otherwise, use the center point.
378         adaptor.SetFocusedActorPosition(actorPosition + actorSize / 2);
379       }
380
381       // Send notification for the change of focus actor
382       mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
383
384       // Save the current focused actor
385       mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
386
387       if(mIsAccessibilityTtsEnabled)
388       {
389         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
390         if(soundPlayer)
391         {
392           if (!mIsFocusSoundFilePathSet)
393           {
394             const std::string soundDirPath = AssetManager::GetDaliSoundPath();
395             mFocusSoundFilePath = soundDirPath + FOCUS_SOUND_FILE_NAME;
396             mIsFocusSoundFilePathSet = true;
397           }
398           soundPlayer.PlaySound(mFocusSoundFilePath);
399         }
400
401         // Play the accessibility attributes with the TTS player.
402         Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
403
404         // Combine attribute texts to one text
405         std::string informationText;
406         for(int i = 0; i < Toolkit::AccessibilityManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
407         {
408           if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
409           {
410             if( i > 0 )
411             {
412               informationText += ", "; // for space time between each information
413             }
414             informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
415           }
416         }
417         player.Play(informationText);
418       }
419
420       return true;
421     }
422   }
423
424   DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
425   return false;
426 }
427
428 Actor AccessibilityManager::GetCurrentFocusActor()
429 {
430   Actor rootActor = Stage::GetCurrent().GetRootLayer();
431   return rootActor.FindChildById(mCurrentFocusActor.second);
432 }
433
434 Actor AccessibilityManager::GetCurrentFocusGroup()
435 {
436   return GetFocusGroup(GetCurrentFocusActor());
437 }
438
439 unsigned int AccessibilityManager::GetCurrentFocusOrder()
440 {
441   return mCurrentFocusActor.first;
442 }
443
444 bool AccessibilityManager::MoveFocusForward()
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, true, mIsWrapped);
454   }
455   else
456   {
457     // TODO: if there is not focused actor, move first actor
458     if(!mFocusIDContainer.empty())
459     {
460       //if there is not focused actor, move 1st actor
461       focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
462       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
463       ret = DoSetCurrentFocusActor((*focusIDIter).second);
464     }
465   }
466
467   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
468
469   return ret;
470 }
471
472 bool AccessibilityManager::MoveFocusBackward()
473 {
474   bool ret = false;
475   mRecursiveFocusMoveCounter = 0;
476
477   FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
478   if(focusIDIter != mFocusIDContainer.end())
479   {
480     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
481     ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
482   }
483   else
484   {
485     // TODO: if there is not focused actor, move last actor
486     if(!mFocusIDContainer.empty())
487     {
488       //if there is not focused actor, move last actor
489       focusIDIter = mFocusIDContainer.end();
490       --focusIDIter;//We want forward iterator to the last element here
491       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
492       ret = DoSetCurrentFocusActor((*focusIDIter).second);
493     }
494   }
495
496   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
497
498   return ret;
499 }
500
501 void AccessibilityManager::DoActivate(Actor actor)
502 {
503   if(actor)
504   {
505     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
506     if(control)
507     {
508       // Notify the control that it is activated
509       GetImplementation( control ).AccessibilityActivate();
510     }
511
512     // Send notification for the activation of focused actor
513     mFocusedActorActivatedSignal.Emit(actor);
514   }
515 }
516
517 void AccessibilityManager::ClearFocus()
518 {
519   Actor actor = GetCurrentFocusActor();
520   if( actor && mFocusIndicatorActor )
521   {
522     actor.Remove( mFocusIndicatorActor );
523   }
524
525   mCurrentFocusActor = FocusIDPair(0, 0);
526
527   // Send notification for the change of focus actor
528   mFocusChangedSignal.Emit(actor, Actor());
529
530   if(mIsAccessibilityTtsEnabled)
531   {
532     // Stop the TTS playing if any
533     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
534     player.Stop();
535   }
536 }
537
538 void AccessibilityManager::Reset()
539 {
540   ClearFocus();
541   mFocusIDContainer.clear();
542   mIDAdditionalInfoContainer.clear();
543 }
544
545 void AccessibilityManager::SetFocusGroup(Actor actor, bool isFocusGroup)
546 {
547   if(actor)
548   {
549     // Create/Set focus group property.
550     actor.RegisterProperty( IS_FOCUS_GROUP, isFocusGroup, Property::READ_WRITE );
551   }
552 }
553
554 bool AccessibilityManager::IsFocusGroup(Actor actor) const
555 {
556   // Check whether the actor is a focus group
557   bool isFocusGroup = false;
558
559   if(actor)
560   {
561     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
562     if(propertyIsFocusGroup != Property::INVALID_INDEX)
563     {
564       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
565     }
566   }
567
568   return isFocusGroup;
569 }
570
571 Actor AccessibilityManager::GetFocusGroup(Actor actor)
572 {
573   // Go through the actor's hierarchy to check which focus group the actor belongs to
574   while (actor && !IsFocusGroup(actor))
575   {
576     actor = actor.GetParent();
577   }
578
579   return actor;
580 }
581
582 Vector2 AccessibilityManager::GetReadPosition() const
583 {
584   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
585   return adaptor.GetReadPosition();
586 }
587
588 void AccessibilityManager::EnableAccessibility(bool enabled)
589 {
590   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Set Enabled Forcibly : %d \n", __FUNCTION__, __LINE__, enabled );
591   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
592   adaptor.EnableAccessibility(enabled);
593 }
594
595 bool AccessibilityManager::IsEnabled() const
596 {
597   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
598   return adaptor.IsEnabled();
599 }
600
601 void AccessibilityManager::SetGroupMode(bool enabled)
602 {
603   mIsFocusWithinGroup = enabled;
604 }
605
606 bool AccessibilityManager::GetGroupMode() const
607 {
608   return mIsFocusWithinGroup;
609 }
610
611 void AccessibilityManager::SetWrapMode(bool wrapped)
612 {
613   mIsWrapped = wrapped;
614 }
615
616 bool AccessibilityManager::GetWrapMode() const
617 {
618   return mIsWrapped;
619 }
620
621 void AccessibilityManager::SetFocusIndicatorActor(Actor indicator)
622 {
623   if( mFocusIndicatorActor != indicator )
624   {
625     Actor currentFocusActor = GetCurrentFocusActor();
626     if( currentFocusActor )
627     {
628       // The new focus indicator should be added to the current focused actor immediately
629       if( mFocusIndicatorActor )
630       {
631         currentFocusActor.Remove( mFocusIndicatorActor );
632       }
633
634       if( indicator )
635       {
636         currentFocusActor.Add( indicator );
637       }
638     }
639
640     mFocusIndicatorActor = indicator;
641   }
642 }
643
644 Actor AccessibilityManager::GetFocusIndicatorActor()
645 {
646   if( ! mFocusIndicatorActor )
647   {
648     // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
649     const std::string imageDirPath = AssetManager::GetDaliImagePath();
650     const std::string focusBorderImagePath = imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME;
651
652     mFocusIndicatorActor = Toolkit::ImageView::New(focusBorderImagePath);
653     mFocusIndicatorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
654     mFocusIndicatorActor.SetProperty( Actor::Property::POSITION_Z,  1.0f );
655
656     // Apply size constraint to the focus indicator
657     mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
658   }
659
660   return mFocusIndicatorActor;
661 }
662
663 bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
664 {
665   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
666   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
667
668   if( (forward && ++focusIDIter == mFocusIDContainer.end())
669     || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
670   {
671     if(mIsEndcapFeedbackEnabled)
672     {
673       if(mIsEndcapFeedbackPlayed == false)
674       {
675         // play sound & skip moving once
676         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
677         if(soundPlayer)
678         {
679           if (!mIsFocusChainEndSoundFilePathSet)
680           {
681             const std::string soundDirPath = AssetManager::GetDaliSoundPath();
682             mFocusChainEndSoundFilePath = soundDirPath + FOCUS_CHAIN_END_SOUND_FILE_NAME;
683             mIsFocusChainEndSoundFilePathSet = true;
684           }
685           soundPlayer.PlaySound(mFocusChainEndSoundFilePath);
686         }
687
688         mIsEndcapFeedbackPlayed = true;
689         return true;
690       }
691       mIsEndcapFeedbackPlayed = false;
692     }
693
694     if(wrapped)
695     {
696       if(forward)
697       {
698         focusIDIter = mFocusIDContainer.begin();
699       }
700       else
701       {
702         focusIDIter = mFocusIDContainer.end();
703         --focusIDIter;//We want forward iterator to the last element here
704       }
705     }
706     else
707     {
708       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
709       // Send notification for handling overshooted situation
710       mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS);
711
712       return false; // Try to move the focus out of the scope
713     }
714   }
715
716   // Invalid focus.
717   if( focusIDIter == mFocusIDContainer.end() )
718   {
719     return false;
720   }
721
722   // Note: This function performs the focus change.
723   if( !DoSetCurrentFocusActor( (*focusIDIter).second ) )
724   {
725     mRecursiveFocusMoveCounter++;
726     if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
727     {
728       // We've attempted to focus all the actors in the whole focus chain and no actor
729       // can be focused successfully.
730       DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
731
732       return false;
733     }
734     else
735     {
736       return DoMoveFocus(focusIDIter, forward, wrapped);
737     }
738   }
739
740   return true;
741 }
742
743 void AccessibilityManager::SetFocusable(Actor actor, bool focusable)
744 {
745   if(actor)
746   {
747     // Create/Set actor focusable property.
748     actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
749   }
750 }
751
752 bool AccessibilityManager::ChangeAccessibilityStatus()
753 {
754   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
755   mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
756   Dali::Toolkit::AccessibilityManager handle( this );
757
758   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] TtsEnabled : %d \n", __FUNCTION__, __LINE__, mIsAccessibilityTtsEnabled );
759
760   if(mIsAccessibilityTtsEnabled)
761   {
762     // Show indicator when tts turned on if there is focused actor.
763     Actor actor = GetCurrentFocusActor();
764     if(actor)
765     {
766       actor.Add( GetFocusIndicatorActor() );
767     }
768     mIsFocusIndicatorEnabled = true;
769
770     // Connect a signal to the TTS player to implement continuous reading mode.
771     Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
772     player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
773     mTtsCreated = true;
774   }
775   else
776   {
777     // Hide indicator when tts turned off
778     Actor actor = GetCurrentFocusActor();
779     if( actor && mFocusIndicatorActor )
780     {
781       actor.Remove( mFocusIndicatorActor );
782     }
783     mIsFocusIndicatorEnabled = false;
784
785     if( mTtsCreated )
786     {
787       // Disconnect the TTS state change signal.
788       Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
789       player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
790       mTtsCreated = true;
791     }
792   }
793
794   mStatusChangedSignal.Emit( handle );
795
796   return true;
797 }
798
799 bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
800 {
801   Dali::Toolkit::AccessibilityManager handle( this );
802   if( !mActionNextSignal.Empty() )
803   {
804     mActionNextSignal.Emit( handle );
805   }
806
807   if(mIsAccessibilityTtsEnabled)
808   {
809     mIsEndcapFeedbackEnabled = allowEndFeedback;
810     return MoveFocusForward();
811   }
812   else
813   {
814     return false;
815   }
816 }
817
818 bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
819 {
820   Dali::Toolkit::AccessibilityManager handle( this );
821   if( !mActionPreviousSignal.Empty() )
822   {
823     mActionPreviousSignal.Emit( handle );
824   }
825
826   if(mIsAccessibilityTtsEnabled)
827   {
828     mIsEndcapFeedbackEnabled = allowEndFeedback;
829     return MoveFocusBackward();
830   }
831   else
832   {
833     return false;
834   }
835 }
836
837 bool AccessibilityManager::AccessibilityActionActivate()
838 {
839   Dali::Toolkit::AccessibilityManager handle( this );
840   if( !mActionActivateSignal.Empty() )
841   {
842     mActionActivateSignal.Emit( handle );
843   }
844
845   bool ret = false;
846
847   Actor actor = GetCurrentFocusActor();
848   if(actor)
849   {
850     DoActivate(actor);
851     ret = true;
852   }
853
854   return ret;
855 }
856
857 bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
858 {
859   Dali::Toolkit::AccessibilityManager handle( this );
860
861   if( allowReadAgain )
862   {
863     if ( !mActionReadSignal.Empty() )
864     {
865       mActionReadSignal.Emit( handle );
866     }
867   }
868   else
869   {
870     if ( !mActionOverSignal.Empty() )
871     {
872       mActionOverSignal.Emit( handle );
873     }
874   }
875
876   bool ret = false;
877
878   if(mIsAccessibilityTtsEnabled)
879   {
880     // Find the focusable actor at the read position
881     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
882     Dali::HitTestAlgorithm::Results results;
883     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
884
885     FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
886     if(focusIDIter != mFocusIDContainer.end())
887     {
888       if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
889       {
890         // Move the focus to the actor
891         ret = SetCurrentFocusActor(results.actor);
892         DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
893       }
894     }
895   }
896
897   return ret;
898 }
899
900 bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
901 {
902   Dali::Toolkit::AccessibilityManager handle( this );
903   if( !mActionReadNextSignal.Empty() )
904   {
905     mActionReadNextSignal.Emit( handle );
906   }
907
908   if(mIsAccessibilityTtsEnabled)
909   {
910     return MoveFocusForward();
911   }
912   else
913   {
914     return false;
915   }
916 }
917
918 bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
919 {
920   Dali::Toolkit::AccessibilityManager handle( this );
921   if( !mActionReadPreviousSignal.Empty() )
922   {
923     mActionReadPreviousSignal.Emit( handle );
924   }
925
926   if(mIsAccessibilityTtsEnabled)
927   {
928     return MoveFocusBackward();
929   }
930   else
931   {
932     return false;
933   }
934 }
935
936 bool AccessibilityManager::AccessibilityActionUp()
937 {
938   Dali::Toolkit::AccessibilityManager handle( this );
939   if( !mActionUpSignal.Empty() )
940   {
941     mActionUpSignal.Emit( handle );
942   }
943
944   bool ret = false;
945
946   if(mIsAccessibilityTtsEnabled)
947   {
948     Actor actor = GetCurrentFocusActor();
949     if(actor)
950     {
951       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
952       if(control)
953       {
954         // Notify the control that it is activated
955         ret = GetImplementation( control ).OnAccessibilityValueChange(true);
956       }
957     }
958   }
959
960   return ret;
961 }
962
963 bool AccessibilityManager::AccessibilityActionDown()
964 {
965   Dali::Toolkit::AccessibilityManager handle( this );
966   if( !mActionDownSignal.Empty() )
967   {
968     mActionDownSignal.Emit( handle );
969   }
970
971   bool ret = false;
972
973   if(mIsAccessibilityTtsEnabled)
974   {
975     Actor actor = GetCurrentFocusActor();
976     if(actor)
977     {
978       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
979       if(control)
980       {
981         // Notify the control that it is activated
982         ret = GetImplementation( control ).OnAccessibilityValueChange(false);
983       }
984     }
985   }
986
987   return ret;
988 }
989
990 bool AccessibilityManager::ClearAccessibilityFocus()
991 {
992   Dali::Toolkit::AccessibilityManager handle( this );
993   if( !mActionClearFocusSignal.Empty() )
994   {
995     mActionClearFocusSignal.Emit( handle );
996   }
997
998   if(mIsAccessibilityTtsEnabled)
999   {
1000     ClearFocus();
1001     return true;
1002   }
1003   else
1004   {
1005     return false;
1006   }
1007 }
1008
1009 bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touch )
1010 {
1011   Dali::Toolkit::AccessibilityManager handle( this );
1012   if( !mActionScrollSignal.Empty() )
1013   {
1014     mActionScrollSignal.Emit( handle, touch );
1015   }
1016
1017   return true;
1018 }
1019
1020 bool AccessibilityManager::AccessibilityActionBack()
1021 {
1022   Dali::Toolkit::AccessibilityManager handle( this );
1023   if( !mActionBackSignal.Empty() )
1024   {
1025     mActionBackSignal.Emit( handle );
1026   }
1027
1028   // TODO: Back to previous view
1029
1030   return mIsAccessibilityTtsEnabled;
1031 }
1032
1033 bool AccessibilityManager::AccessibilityActionScrollUp()
1034 {
1035   Dali::Toolkit::AccessibilityManager handle( this );
1036   if( !mActionScrollUpSignal.Empty() )
1037   {
1038     mActionScrollUpSignal.Emit( handle );
1039   }
1040
1041   bool ret = false;
1042
1043   if(mIsAccessibilityTtsEnabled)
1044   {
1045     Actor actor = GetCurrentFocusActor();
1046     if(actor)
1047     {
1048       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1049       if(control)
1050       {
1051         // TODO: Notify the control to scroll up. Should control handle this?
1052 //        ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
1053       }
1054     }
1055   }
1056
1057   return ret;
1058 }
1059
1060 bool AccessibilityManager::AccessibilityActionScrollDown()
1061 {
1062   Dali::Toolkit::AccessibilityManager handle( this );
1063   if( !mActionScrollDownSignal.Empty() )
1064   {
1065     mActionScrollDownSignal.Emit( handle );
1066   }
1067
1068   bool ret = false;
1069
1070   if(mIsAccessibilityTtsEnabled)
1071   {
1072     Actor actor = GetCurrentFocusActor();
1073     if(actor)
1074     {
1075       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1076       if(control)
1077       {
1078         // TODO: Notify the control to scroll down. Should control handle this?
1079 //        ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
1080       }
1081     }
1082   }
1083
1084   return ret;
1085 }
1086
1087 bool AccessibilityManager::AccessibilityActionPageLeft()
1088 {
1089   Dali::Toolkit::AccessibilityManager handle( this );
1090   if( !mActionPageLeftSignal.Empty() )
1091   {
1092     mActionPageLeftSignal.Emit( handle );
1093   }
1094
1095   bool ret = false;
1096
1097   if(mIsAccessibilityTtsEnabled)
1098   {
1099     Actor actor = GetCurrentFocusActor();
1100     if(actor)
1101     {
1102       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1103       if(control)
1104       {
1105         // TODO: Notify the control to scroll left to the previous page. Should control handle this?
1106 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
1107       }
1108     }
1109   }
1110
1111   return ret;
1112 }
1113
1114 bool AccessibilityManager::AccessibilityActionPageRight()
1115 {
1116   Dali::Toolkit::AccessibilityManager handle( this );
1117   if( !mActionPageRightSignal.Empty() )
1118   {
1119     mActionPageRightSignal.Emit( handle );
1120   }
1121
1122   bool ret = false;
1123
1124   if(mIsAccessibilityTtsEnabled)
1125   {
1126     Actor actor = GetCurrentFocusActor();
1127     if(actor)
1128     {
1129       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1130       if(control)
1131       {
1132         // TODO: Notify the control to scroll right to the next page. Should control handle this?
1133 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
1134       }
1135     }
1136   }
1137
1138   return ret;
1139 }
1140
1141 bool AccessibilityManager::AccessibilityActionPageUp()
1142 {
1143   Dali::Toolkit::AccessibilityManager handle( this );
1144   if( !mActionPageUpSignal.Empty() )
1145   {
1146     mActionPageUpSignal.Emit( handle );
1147   }
1148
1149   bool ret = false;
1150
1151   if(mIsAccessibilityTtsEnabled)
1152   {
1153     Actor actor = GetCurrentFocusActor();
1154     if(actor)
1155     {
1156       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1157       if(control)
1158       {
1159         // TODO: Notify the control to scroll up to the previous page. Should control handle this?
1160 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
1161       }
1162     }
1163   }
1164
1165   return ret;
1166 }
1167
1168 bool AccessibilityManager::AccessibilityActionPageDown()
1169 {
1170   Dali::Toolkit::AccessibilityManager handle( this );
1171   if( !mActionPageDownSignal.Empty() )
1172   {
1173     mActionPageDownSignal.Emit( handle );
1174   }
1175
1176   bool ret = false;
1177
1178   if(mIsAccessibilityTtsEnabled)
1179   {
1180     Actor actor = GetCurrentFocusActor();
1181     if(actor)
1182     {
1183       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1184       if(control)
1185       {
1186         // TODO: Notify the control to scroll down to the next page. Should control handle this?
1187 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
1188       }
1189     }
1190   }
1191
1192   return ret;
1193 }
1194
1195 bool AccessibilityManager::AccessibilityActionMoveToFirst()
1196 {
1197   Dali::Toolkit::AccessibilityManager handle( this );
1198   if( !mActionMoveToFirstSignal.Empty() )
1199   {
1200     mActionMoveToFirstSignal.Emit( handle );
1201   }
1202
1203   // TODO: Move to the first item on screen
1204
1205   return mIsAccessibilityTtsEnabled;
1206 }
1207
1208 bool AccessibilityManager::AccessibilityActionMoveToLast()
1209 {
1210   Dali::Toolkit::AccessibilityManager handle( this );
1211   if( !mActionMoveToLastSignal.Empty() )
1212   {
1213     mActionMoveToLastSignal.Emit( handle );
1214   }
1215
1216   // TODO: Move to the last item on screen
1217
1218   return mIsAccessibilityTtsEnabled;
1219 }
1220
1221 bool AccessibilityManager::AccessibilityActionReadFromTop()
1222 {
1223   Dali::Toolkit::AccessibilityManager handle( this );
1224   if( !mActionReadFromTopSignal.Empty() )
1225   {
1226     mActionReadFromTopSignal.Emit( handle );
1227   }
1228
1229   // TODO: Move to the top item on screen and read from the item continuously
1230
1231   return mIsAccessibilityTtsEnabled;
1232 }
1233
1234 bool AccessibilityManager::AccessibilityActionReadFromNext()
1235 {
1236   Dali::Toolkit::AccessibilityManager handle( this );
1237
1238   if( !mActionReadFromNextSignal.Empty() )
1239   {
1240     mActionReadFromNextSignal.Emit( handle );
1241   }
1242
1243   if( mIsAccessibilityTtsEnabled )
1244   {
1245     // Mark that we are in continuous play mode, so TTS signals can move focus.
1246     mContinuousPlayMode = true;
1247
1248     // Attempt to move to the next item and read from the item continuously.
1249     MoveFocusForward();
1250   }
1251
1252   return mIsAccessibilityTtsEnabled;
1253 }
1254
1255 void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
1256 {
1257   if( mContinuousPlayMode )
1258   {
1259     // If we were playing and now we have stopped, attempt to play the next item.
1260     if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
1261     {
1262       // Attempt to move the focus forward and play.
1263       // If we can't cancel continuous play mode.
1264       if( !MoveFocusForward() )
1265       {
1266         // We are done, exit continuous play mode.
1267         mContinuousPlayMode = false;
1268       }
1269     }
1270     else
1271     {
1272       // Unexpected play state change, exit continuous play mode.
1273       mContinuousPlayMode = false;
1274     }
1275   }
1276 }
1277
1278 bool AccessibilityManager::AccessibilityActionZoom()
1279 {
1280   Dali::Toolkit::AccessibilityManager handle( this );
1281   if( !mActionZoomSignal.Empty() )
1282   {
1283     mActionZoomSignal.Emit( handle );
1284   }
1285
1286   bool ret = false;
1287
1288   if(mIsAccessibilityTtsEnabled)
1289   {
1290     Actor actor = GetCurrentFocusActor();
1291     if(actor)
1292     {
1293       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1294       if(control)
1295       {
1296         // Notify the control to zoom
1297         ret = GetImplementation( control ).OnAccessibilityZoom();
1298       }
1299     }
1300   }
1301
1302   return ret;
1303 }
1304
1305 bool AccessibilityManager::AccessibilityActionReadPauseResume()
1306 {
1307   Dali::Toolkit::AccessibilityManager handle( this );
1308   if( !mActionReadPauseResumeSignal.Empty() )
1309   {
1310     mActionReadPauseResumeSignal.Emit( handle );
1311   }
1312
1313   bool ret = false;
1314
1315   if(mIsAccessibilityTtsEnabled)
1316   {
1317     // Pause or resume the TTS player
1318     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
1319     Dali::TtsPlayer::State state = player.GetState();
1320     if(state == Dali::TtsPlayer::PLAYING)
1321     {
1322       player.Pause();
1323       ret = true;
1324     }
1325     else if(state == Dali::TtsPlayer::PAUSED)
1326     {
1327       player.Resume();
1328       ret = true;
1329     }
1330   }
1331
1332   return ret;
1333 }
1334
1335 bool AccessibilityManager::AccessibilityActionStartStop()
1336 {
1337   Dali::Toolkit::AccessibilityManager handle( this );
1338   if( !mActionStartStopSignal.Empty() )
1339   {
1340     mActionStartStopSignal.Emit( handle );
1341   }
1342
1343   // TODO: Start/stop the current action
1344
1345   return mIsAccessibilityTtsEnabled;
1346 }
1347
1348 bool AccessibilityManager::AccessibilityActionForwardToApp()
1349 {
1350   Dali::Toolkit::AccessibilityManager handle( this );
1351   if( !mActionForwardSignal.Empty() )
1352   {
1353     mActionForwardSignal.Emit( handle );
1354   }
1355
1356   return mIsAccessibilityTtsEnabled;
1357 }
1358
1359 bool AccessibilityManager::HandlePanGesture(const AccessibilityGestureEvent& panEvent)
1360 {
1361   bool handled = false;
1362
1363   if( panEvent.state == AccessibilityGestureEvent::STARTED )
1364   {
1365     // Find the focusable actor at the event position
1366     Dali::HitTestAlgorithm::Results results;
1367     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
1368
1369     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
1370     mCurrentGesturedActor = results.actor;
1371
1372     if(!mCurrentGesturedActor)
1373     {
1374       DALI_LOG_ERROR("Gesture detected, but no hit actor\n");
1375     }
1376   }
1377
1378   // GestureState::FINISHED (Up) events are delivered with previous (Motion) event position
1379   // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
1380   if ( AccessibilityGestureEvent::FINISHED != panEvent.state )
1381   {
1382     // Store the previous position for next GestureState::FINISHED iteration.
1383     mPreviousPosition = panEvent.previousPosition;
1384   }
1385
1386   Actor rootActor = Stage::GetCurrent().GetRootLayer();
1387
1388   Dali::PanGesture pan = DevelPanGesture::New( static_cast<Dali::GestureState>(panEvent.state) );
1389   DevelPanGesture::SetTime( pan, panEvent.time );
1390   DevelPanGesture::SetNumberOfTouches( pan, panEvent.numberOfTouches  );
1391   DevelPanGesture::SetScreenPosition( pan, panEvent.currentPosition );
1392   DevelPanGesture::SetScreenDisplacement( pan, mPreviousPosition - panEvent.currentPosition );
1393   // Avoid dividing by 0
1394   if(panEvent.timeDelta > 0)
1395   {
1396     DevelPanGesture::SetScreenVelocity( pan, Vector2( pan.GetScreenDisplacement().x / panEvent.timeDelta, pan.GetScreenDisplacement().y / panEvent.timeDelta ) );
1397   }
1398
1399   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
1400   while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
1401   {
1402     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
1403     if(control)
1404     {
1405       Vector2 localCurrent;
1406       control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
1407       DevelPanGesture::SetPosition( pan, localCurrent );
1408
1409       Vector2 localPrevious;
1410       control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
1411
1412       DevelPanGesture::SetDisplacement( pan, localCurrent - localPrevious );
1413       // Avoid dividing by 0
1414       if(panEvent.timeDelta > 0)
1415       {
1416         DevelPanGesture::SetVelocity( pan, Vector2( pan.GetDisplacement().x / panEvent.timeDelta, pan.GetDisplacement().y / panEvent.timeDelta ));
1417       }
1418
1419       handled = GetImplementation( control ).OnAccessibilityPan(pan);
1420     }
1421
1422     // If the gesture is not handled by the control, check its parent
1423     if(!handled)
1424     {
1425       mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
1426
1427       if(!mCurrentGesturedActor)
1428       {
1429         DALI_LOG_ERROR("no more gestured actor\n");
1430       }
1431     }
1432     else
1433     {
1434       // If handled, then update the pan gesture properties
1435       PanGestureDetector::SetPanGestureProperties( pan );
1436     }
1437   }
1438
1439   return handled;
1440 }
1441
1442 Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
1443 {
1444   return mFocusChangedSignal;
1445 }
1446
1447 Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
1448 {
1449   return mFocusOvershotSignal;
1450 }
1451
1452 Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
1453 {
1454   return mFocusedActorActivatedSignal;
1455 }
1456
1457 } // namespace Internal
1458
1459 } // namespace Toolkit
1460
1461 } // namespace Dali