1fcc519c09f76b59878fc3afa3c4b9c1c254f001
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / focus-manager-impl.cpp
1 /*
2  * Copyright (c) 2014 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 "focus-manager-impl.h"
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/layer.h>
23 #include <dali/public-api/adaptor-framework/accessibility-manager.h>
24 #include <dali/public-api/adaptor-framework/sound-player.h>
25 #include <dali/public-api/adaptor-framework/tts-player.h>
26 #include <dali/public-api/animation/constraints.h>
27 #include <dali/public-api/events/hit-test-algorithm.h>
28 #include <dali/public-api/images/resource-image.h>
29
30 // INTERNAL INCLUDES
31 #include <dali-toolkit/public-api/controls/control.h>
32 #include <dali-toolkit/public-api/controls/control-impl.h>
33 #include <dali/integration-api/debug.h>
34
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace // unnamed namespace
45 {
46
47 #if defined(DEBUG_ENABLED)
48 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
49 #endif
50
51 const char * const ACTOR_FOCUSABLE("focusable");
52 const char * const IS_FOCUS_GROUP("is-focus-group");
53
54 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
55 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
56
57 const char* FOCUS_SOUND_FILE = DALI_SOUND_DIR "Focus.ogg";
58 const char* FOCUS_CHAIN_END_SOUND_FILE = DALI_SOUND_DIR "End_of_List.ogg";
59
60 /**
61  * The function to be used in the hit-test algorithm to check whether the actor is hittable.
62  */
63 bool IsActorFocusableFunction(Actor actor, Dali::HitTestAlgorithm::TraverseType type)
64 {
65   bool hittable = false;
66
67   switch (type)
68   {
69     case Dali::HitTestAlgorithm::CHECK_ACTOR:
70     {
71       // Check whether the actor is visible and not fully transparent.
72       if( actor.IsVisible()
73        && actor.GetCurrentWorldColor().a > 0.01f) // not FULLY_TRANSPARENT
74       {
75         // Check whether the actor is focusable
76         Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
77         if(propertyActorFocusable != Property::INVALID_INDEX)
78         {
79           hittable = actor.GetProperty<bool>(propertyActorFocusable);
80         }
81       }
82       break;
83     }
84     case Dali::HitTestAlgorithm::DESCEND_ACTOR_TREE:
85     {
86       if( actor.IsVisible() ) // Actor is visible, if not visible then none of its children are visible.
87       {
88         hittable = true;
89       }
90       break;
91     }
92     default:
93     {
94       break;
95     }
96   }
97
98   return hittable;
99 };
100
101 }
102
103 FocusManager::FocusManager()
104 : mIsWrapped(false),
105   mIsFocusWithinGroup(false),
106   mIsEndcapFeedbackEnabled(false),
107   mIsEndcapFeedbackPlayed(false),
108   mCurrentFocusActor(FocusIDPair(0, 0)),
109   mFocusIndicatorActor(Actor()),
110   mRecursiveFocusMoveCounter(0),
111   mIsAccessibilityTtsEnabled(false),
112   mIsFocusIndicatorEnabled(false)
113 {
114   CreateDefaultFocusIndicatorActor();
115
116   AccessibilityManager manager = AccessibilityManager::Get();
117   manager.SetActionHandler(*this);
118   manager.SetGestureHandler(*this);
119
120   ChangeAccessibilityStatus();
121 }
122
123 FocusManager::~FocusManager()
124 {
125 }
126
127 FocusManager::ActorAdditionalInfo FocusManager::GetActorAdditionalInfo(const unsigned int actorID) const
128 {
129   ActorAdditionalInfo data;
130   IDAdditionalInfoConstIter iter = mIDAdditionalInfoContainer.find(actorID);
131   if(iter != mIDAdditionalInfoContainer.end())
132   {
133     data = (*iter).second;
134   }
135
136   return data;
137 }
138
139 void FocusManager::SynchronizeActorAdditionalInfo(const unsigned int actorID, const unsigned int order)
140 {
141   ActorAdditionalInfo actorInfo = GetActorAdditionalInfo(actorID);
142   actorInfo.mFocusOrder = order;
143   mIDAdditionalInfoContainer.erase(actorID);
144   mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, actorInfo));
145 }
146
147 void FocusManager::SetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type, const std::string& text)
148 {
149   if(actor)
150   {
151     unsigned int actorID = actor.GetId();
152
153     ActorAdditionalInfo info = GetActorAdditionalInfo(actorID);
154     info.mAccessibilityAttributes[type] = text;
155
156     mIDAdditionalInfoContainer.erase(actorID);
157     mIDAdditionalInfoContainer.insert(IDAdditionalInfoPair(actorID, info));
158   }
159 }
160
161 std::string FocusManager::GetAccessibilityAttribute(Actor actor, Toolkit::FocusManager::AccessibilityAttribute type) const
162 {
163   std::string text;
164
165   if(actor)
166   {
167     ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
168     text = data.mAccessibilityAttributes[type];
169   }
170
171   return text;
172 }
173
174 void FocusManager::SetFocusOrder(Actor actor, const unsigned int order)
175 {
176   // Do nothing if the focus order of the actor is not changed.
177   if(actor && GetFocusOrder(actor) != order)
178   {
179     // Firstly delete the actor from the focus chain if it's already there with a different focus order.
180     mFocusIDContainer.erase(GetFocusOrder(actor));
181
182     // Create actor focusable property if not already created.
183     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
184     if(propertyActorFocusable == Property::INVALID_INDEX)
185     {
186       propertyActorFocusable = actor.RegisterProperty(ACTOR_FOCUSABLE, true);
187     }
188
189     if(order == 0)
190     {
191       // The actor is not focusable without a defined focus order.
192       actor.SetProperty(propertyActorFocusable, false);
193
194       // If the actor is currently being focused, it should clear the focus
195       if(actor == GetCurrentFocusActor())
196       {
197         ClearFocus();
198       }
199     }
200     else // Insert the actor to the focus chain
201     {
202       // Check whether there is another actor in the focus chain with the same focus order already.
203       FocusIDIter focusIDIter = mFocusIDContainer.find(order);
204       if(focusIDIter != mFocusIDContainer.end())
205       {
206         // We need to increase the focus order of that actor and all the actors followed it
207         // in the focus chain.
208         FocusIDIter lastIter = mFocusIDContainer.end();
209         --lastIter;//We want forward iterator to the last element here
210         mFocusIDContainer.insert(FocusIDPair((*lastIter).first + 1, (*lastIter).second));
211
212         // Update the actor's focus order in its additional data
213         SynchronizeActorAdditionalInfo((*lastIter).second, (*lastIter).first + 1);
214
215         for(FocusIDIter iter = lastIter; iter != focusIDIter; iter--)
216         {
217           FocusIDIter previousIter = iter;
218           --previousIter;//We want forward iterator to the previous element here
219           unsigned int actorID = (*previousIter).second;
220           (*iter).second = actorID;
221
222           // Update the actor's focus order in its additional data
223           SynchronizeActorAdditionalInfo(actorID, (*iter).first);
224         }
225
226         mFocusIDContainer.erase(order);
227       }
228
229       // The actor is focusable
230       actor.SetProperty(propertyActorFocusable, true);
231
232       // Now we insert the actor into the focus chain with the specified focus order
233       mFocusIDContainer.insert(FocusIDPair(order, actor.GetId()));
234     }
235
236     // Update the actor's focus order in its additional data
237     SynchronizeActorAdditionalInfo(actor.GetId(), order);
238   }
239 }
240
241 unsigned int FocusManager::GetFocusOrder(Actor actor) const
242 {
243   unsigned int focusOrder = 0;
244
245   if(actor)
246   {
247     ActorAdditionalInfo data = GetActorAdditionalInfo(actor.GetId());
248     focusOrder = data.mFocusOrder;
249   }
250
251   return focusOrder;
252 }
253
254 unsigned int FocusManager::GenerateNewFocusOrder() const
255 {
256   unsigned int order = 1;
257   FocusIDContainer::const_reverse_iterator iter = mFocusIDContainer.rbegin();
258
259   if(iter != mFocusIDContainer.rend())
260   {
261     order = (*iter).first + 1;
262   }
263
264   return order;
265 }
266
267 Actor FocusManager::GetActorByFocusOrder(const unsigned int order)
268 {
269   Actor actor = Actor();
270
271   FocusIDIter focusIDIter = mFocusIDContainer.find(order);
272   if(focusIDIter != mFocusIDContainer.end())
273   {
274     Actor rootActor = Stage::GetCurrent().GetRootLayer();
275     actor = rootActor.FindChildById(mFocusIDContainer[order]);
276   }
277
278   return actor;
279 }
280
281 bool FocusManager::SetCurrentFocusActor(Actor actor)
282 {
283   if(actor)
284   {
285     return DoSetCurrentFocusActor(actor.GetId());
286   }
287
288   return false;
289 }
290
291 bool FocusManager::DoSetCurrentFocusActor(const unsigned int actorID)
292 {
293   Actor rootActor = Stage::GetCurrent().GetRootLayer();
294
295   // If the group mode is enabled, check which focus group the current focused actor belongs to
296   Actor focusGroup;
297   if(mIsFocusWithinGroup)
298   {
299     focusGroup = GetFocusGroup(GetCurrentFocusActor());
300   }
301
302   if(!focusGroup)
303   {
304     focusGroup = rootActor;
305   }
306
307   Actor actor = focusGroup.FindChildById(actorID);
308
309   // Check whether the actor is in the stage
310   if(actor)
311   {
312     // Check whether the actor is focusable
313     bool actorFocusable = false;
314     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
315     if(propertyActorFocusable != Property::INVALID_INDEX)
316     {
317       actorFocusable = actor.GetProperty<bool>(propertyActorFocusable);
318     }
319
320     // Go through the actor's hierarchy to check whether the actor is visible
321     bool actorVisible = actor.IsVisible();
322     Actor parent = actor.GetParent();
323     while (actorVisible && parent && parent != rootActor)
324     {
325       actorVisible = parent.IsVisible();
326       parent = parent.GetParent();
327     }
328
329     // Check whether the actor is fully transparent
330     bool actorOpaque = actor.GetCurrentWorldColor().a > 0.01f;
331
332     // Set the focus only when the actor is focusable and visible and not fully transparent
333     if(actorVisible && actorFocusable && actorOpaque)
334     {
335       // Draw the focus indicator upon the focused actor
336       if(mIsFocusIndicatorEnabled && mFocusIndicatorActor)
337       {
338         actor.Add(mFocusIndicatorActor);
339       }
340
341       // Send notification for the change of focus actor
342       mFocusChangedSignal.Emit( GetCurrentFocusActor(), actor );
343
344       // Save the current focused actor
345       mCurrentFocusActor = FocusIDPair(GetFocusOrder(actor), actorID);
346
347       if(mIsAccessibilityTtsEnabled)
348       {
349         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
350         if(soundPlayer)
351         {
352           soundPlayer.PlaySound(FOCUS_SOUND_FILE);
353         }
354
355         // Play the accessibility attributes with the TTS player.
356         Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
357
358         // Combine attribute texts to one text
359         std::string informationText;
360         for(int i = 0; i < Toolkit::FocusManager::ACCESSIBILITY_ATTRIBUTE_NUM; i++)
361         {
362           if(!GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i].empty())
363           {
364             if( i > 0 )
365             {
366               informationText += ", "; // for space time between each information
367             }
368             informationText += GetActorAdditionalInfo(actorID).mAccessibilityAttributes[i];
369           }
370         }
371         player.Play(informationText);
372       }
373
374       return true;
375     }
376   }
377
378   DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
379   return false;
380 }
381
382 Actor FocusManager::GetCurrentFocusActor()
383 {
384   Actor rootActor = Stage::GetCurrent().GetRootLayer();
385   return rootActor.FindChildById(mCurrentFocusActor.second);
386 }
387
388 Actor FocusManager::GetCurrentFocusGroup()
389 {
390   return GetFocusGroup(GetCurrentFocusActor());
391 }
392
393 unsigned int FocusManager::GetCurrentFocusOrder()
394 {
395   return mCurrentFocusActor.first;
396 }
397
398 bool FocusManager::MoveFocusForward()
399 {
400   bool ret = false;
401   mRecursiveFocusMoveCounter = 0;
402
403   FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
404   if(focusIDIter != mFocusIDContainer.end())
405   {
406     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
407     ret = DoMoveFocus(focusIDIter, true, mIsWrapped);
408   }
409   else
410   {
411     // TODO: if there is not focused actor, move first actor
412     if(!mFocusIDContainer.empty())
413     {
414       //if there is not focused actor, move 1st actor
415       focusIDIter = mFocusIDContainer.begin(); // TODO: I'm not sure it was sorted.
416       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
417       ret = DoSetCurrentFocusActor((*focusIDIter).second);
418     }
419   }
420
421   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
422
423   return ret;
424 }
425
426 bool FocusManager::MoveFocusBackward()
427 {
428   bool ret = false;
429   mRecursiveFocusMoveCounter = 0;
430
431   FocusIDIter focusIDIter = mFocusIDContainer.find(mCurrentFocusActor.first);
432   if(focusIDIter != mFocusIDContainer.end())
433   {
434     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
435     ret = DoMoveFocus(focusIDIter, false, mIsWrapped);
436   }
437   else
438   {
439     // TODO: if there is not focused actor, move last actor
440     if(!mFocusIDContainer.empty())
441     {
442       //if there is not focused actor, move last actor
443       focusIDIter = mFocusIDContainer.end();
444       --focusIDIter;//We want forward iterator to the last element here
445       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
446       ret = DoSetCurrentFocusActor((*focusIDIter).second);
447     }
448   }
449
450   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s] %s\n", __FUNCTION__, ret?"SUCCEED!!!":"FAILED!!!");
451
452   return ret;
453 }
454
455 void FocusManager::DoActivate(Actor actor)
456 {
457   if(actor)
458   {
459     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
460     if(control)
461     {
462       // Notify the control that it is activated
463       control.GetImplementation().Activate();
464     }
465
466     // Send notification for the activation of focused actor
467     mFocusedActorActivatedSignal.Emit(actor);
468   }
469 }
470
471 void FocusManager::ClearFocus()
472 {
473   Actor actor = GetCurrentFocusActor();
474   if(actor)
475   {
476     actor.Remove(mFocusIndicatorActor);
477   }
478
479   mCurrentFocusActor = FocusIDPair(0, 0);
480
481   // Send notification for the change of focus actor
482   mFocusChangedSignal.Emit(actor, Actor());
483
484   if(mIsAccessibilityTtsEnabled)
485   {
486     // Stop the TTS playing if any
487     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
488     player.Stop();
489   }
490 }
491
492 void FocusManager::Reset()
493 {
494   ClearFocus();
495   mFocusIDContainer.clear();
496   mIDAdditionalInfoContainer.clear();
497 }
498
499 void FocusManager::SetFocusGroup(Actor actor, bool isFocusGroup)
500 {
501   if(actor)
502   {
503     // Create focus group property if not already created.
504     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
505     if(propertyIsFocusGroup == Property::INVALID_INDEX)
506     {
507       actor.RegisterProperty(IS_FOCUS_GROUP, isFocusGroup);
508     }
509     else
510     {
511       actor.SetProperty(propertyIsFocusGroup, isFocusGroup);
512     }
513   }
514 }
515
516 bool FocusManager::IsFocusGroup(Actor actor) const
517 {
518   // Check whether the actor is a focus group
519   bool isFocusGroup = false;
520
521   if(actor)
522   {
523     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP);
524     if(propertyIsFocusGroup != Property::INVALID_INDEX)
525     {
526       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
527     }
528   }
529
530   return isFocusGroup;
531 }
532
533 Actor FocusManager::GetFocusGroup(Actor actor)
534 {
535   // Go through the actor's hierarchy to check which focus group the actor belongs to
536   while (actor && !IsFocusGroup(actor))
537   {
538     actor = actor.GetParent();
539   }
540
541   return actor;
542 }
543
544 void FocusManager::SetGroupMode(bool enabled)
545 {
546   mIsFocusWithinGroup = enabled;
547 }
548
549 bool FocusManager::GetGroupMode() const
550 {
551   return mIsFocusWithinGroup;
552 }
553
554 void FocusManager::SetWrapMode(bool wrapped)
555 {
556   mIsWrapped = wrapped;
557 }
558
559 bool FocusManager::GetWrapMode() const
560 {
561   return mIsWrapped;
562 }
563
564 void FocusManager::SetFocusIndicatorActor(Actor indicator)
565 {
566   mFocusIndicatorActor = indicator;
567 }
568
569 Actor FocusManager::GetFocusIndicatorActor()
570 {
571   return mFocusIndicatorActor;
572 }
573
574 bool FocusManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
575 {
576   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
577   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
578
579   if( (forward && ++focusIDIter == mFocusIDContainer.end())
580     || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
581   {
582     if(mIsEndcapFeedbackEnabled)
583     {
584       if(mIsEndcapFeedbackPlayed == false)
585       {
586         // play sound & skip moving once
587         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
588         if(soundPlayer)
589         {
590           soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
591         }
592
593         mIsEndcapFeedbackPlayed = true;
594         return true;
595       }
596       mIsEndcapFeedbackPlayed = false;
597     }
598
599     if(wrapped)
600     {
601       if(forward)
602       {
603         focusIDIter = mFocusIDContainer.begin();
604       }
605       else
606       {
607         focusIDIter = mFocusIDContainer.end();
608         --focusIDIter;//We want forward iterator to the last element here
609       }
610     }
611     else
612     {
613       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
614       // Send notification for handling overshooted situation
615       mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::FocusManager::OVERSHOT_NEXT : Toolkit::FocusManager::OVERSHOT_PREVIOUS);
616
617       return false; // Try to move the focus out of the scope
618     }
619   }
620
621   if((focusIDIter != mFocusIDContainer.end()) && !DoSetCurrentFocusActor((*focusIDIter).second))
622   {
623     mRecursiveFocusMoveCounter++;
624     if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
625     {
626       // We've attempted to focus all the actors in the whole focus chain and no actor
627       // can be focused successfully.
628
629       DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
630
631       return false;
632     }
633     else
634     {
635       return DoMoveFocus(focusIDIter, forward, wrapped);
636     }
637   }
638
639   return true;
640 }
641
642 void FocusManager::SetFocusable(Actor actor, bool focusable)
643 {
644   if(actor)
645   {
646     // Create actor focusable property if not already created.
647     Property::Index propertyActorFocusable = actor.GetPropertyIndex(ACTOR_FOCUSABLE);
648     if(propertyActorFocusable == Property::INVALID_INDEX)
649     {
650       actor.RegisterProperty(ACTOR_FOCUSABLE, focusable);
651     }
652     else
653     {
654       actor.SetProperty(propertyActorFocusable, focusable);
655     }
656   }
657 }
658
659 void FocusManager::CreateDefaultFocusIndicatorActor()
660 {
661   // Create a focus indicator actor shared by all the focusable actors
662   Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
663
664   ImageActor focusIndicator = ImageActor::New(borderImage);
665   focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
666   focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
667   focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
668   focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
669
670   // Apply size constraint to the focus indicator
671   focusIndicator.SetSizeMode( SIZE_EQUAL_TO_PARENT );
672
673   SetFocusIndicatorActor(focusIndicator);
674 }
675
676 bool FocusManager::ChangeAccessibilityStatus()
677 {
678   AccessibilityManager manager = AccessibilityManager::Get();
679   mIsAccessibilityTtsEnabled = manager.IsEnabled();
680
681   if(mIsAccessibilityTtsEnabled)
682   {
683     // Show indicator when tts turned on if there is focused actor.
684     Actor actor = GetCurrentFocusActor();
685     if(actor)
686     {
687       if(mFocusIndicatorActor)
688       {
689         actor.Add(mFocusIndicatorActor);
690       }
691     }
692     mIsFocusIndicatorEnabled = true;
693   }
694   else
695   {
696     // Hide indicator when tts turned off
697     Actor actor = GetCurrentFocusActor();
698     if(actor)
699     {
700       actor.Remove(mFocusIndicatorActor);
701     }
702     mIsFocusIndicatorEnabled = false;
703   }
704
705   return true;
706 }
707
708 bool FocusManager::AccessibilityActionNext(bool allowEndFeedback)
709 {
710   if(mIsAccessibilityTtsEnabled)
711   {
712     mIsEndcapFeedbackEnabled = allowEndFeedback;
713     return MoveFocusForward();
714   }
715   else
716   {
717     return false;
718   }
719 }
720
721 bool FocusManager::AccessibilityActionPrevious(bool allowEndFeedback)
722 {
723   if(mIsAccessibilityTtsEnabled)
724   {
725     mIsEndcapFeedbackEnabled = allowEndFeedback;
726     return MoveFocusBackward();
727   }
728   else
729   {
730     return false;
731   }
732 }
733
734 bool FocusManager::AccessibilityActionActivate()
735 {
736   bool ret = false;
737
738   Actor actor = GetCurrentFocusActor();
739   if(actor)
740   {
741     DoActivate(actor);
742     ret = true;
743   }
744
745   return ret;
746 }
747
748 bool FocusManager::AccessibilityActionRead(bool allowReadAgain)
749 {
750   bool ret = false;
751
752   if(mIsAccessibilityTtsEnabled)
753   {
754     // Find the focusable actor at the read position
755     AccessibilityManager manager = AccessibilityManager::Get();
756     Dali::HitTestAlgorithm::Results results;
757     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), manager.GetReadPosition(), results, IsActorFocusableFunction );
758
759     FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
760     if(focusIDIter != mFocusIDContainer.end())
761     {
762       if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
763       {
764         // Move the focus to the actor
765         ret = SetCurrentFocusActor(results.actor);
766         DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
767       }
768     }
769   }
770
771   return ret;
772 }
773
774 bool FocusManager::AccessibilityActionReadNext(bool allowEndFeedback)
775 {
776   if(mIsAccessibilityTtsEnabled)
777   {
778     return MoveFocusForward();
779   }
780   else
781   {
782     return false;
783   }
784 }
785
786 bool FocusManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
787 {
788   if(mIsAccessibilityTtsEnabled)
789   {
790     return MoveFocusBackward();
791   }
792   else
793   {
794     return false;
795   }
796 }
797
798 bool FocusManager::AccessibilityActionUp()
799 {
800   bool ret = false;
801
802   if(mIsAccessibilityTtsEnabled)
803   {
804     Actor actor = GetCurrentFocusActor();
805     if(actor)
806     {
807       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
808       if(control)
809       {
810         // Notify the control that it is activated
811         ret = control.GetImplementation().OnAccessibilityValueChange(true);
812       }
813     }
814   }
815
816   return ret;
817 }
818
819 bool FocusManager::AccessibilityActionDown()
820 {
821   bool ret = false;
822
823   if(mIsAccessibilityTtsEnabled)
824   {
825     Actor actor = GetCurrentFocusActor();
826     if(actor)
827     {
828       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
829       if(control)
830       {
831         // Notify the control that it is activated
832         ret = control.GetImplementation().OnAccessibilityValueChange(false);
833       }
834     }
835   }
836
837   return ret;
838 }
839
840 bool FocusManager::ClearAccessibilityFocus()
841 {
842   if(mIsAccessibilityTtsEnabled)
843   {
844     ClearFocus();
845     return true;
846   }
847   else
848   {
849     return false;
850   }
851 }
852
853 bool FocusManager::AccessibilityActionBack()
854 {
855   // TODO: Back to previous view
856
857   return mIsAccessibilityTtsEnabled;
858 }
859
860 bool FocusManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
861 {
862   bool handled = false;
863
864   // TODO: Need to convert the touchevent for the focused actor?
865
866   Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
867   if(control)
868   {
869     handled = control.GetImplementation().OnAccessibilityTouch(touchEvent);
870   }
871
872   return handled;
873 }
874
875 bool FocusManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
876 {
877   bool handled = false;
878
879   if( panEvent.state == Gesture::Started )
880   {
881     // Find the focusable actor at the event position
882     Dali::HitTestAlgorithm::Results results;
883     AccessibilityManager manager = AccessibilityManager::Get();
884
885     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
886     mCurrentGesturedActor = results.actor;
887
888     if(!mCurrentGesturedActor)
889     {
890       DALI_LOG_ERROR("Gesture detected, but no hit actor");
891     }
892   }
893
894   // Gesture::Finished (Up) events are delivered with previous (Motion) event position
895   // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
896   if ( Gesture::Finished != panEvent.state )
897   {
898     // Store the previous position for next Gesture::Finished iteration.
899     mPreviousPosition = panEvent.previousPosition;
900   }
901
902   Actor rootActor = Stage::GetCurrent().GetRootLayer();
903
904   Dali::PanGesture pan(panEvent.state);
905   pan.time = panEvent.time;
906   pan.numberOfTouches = panEvent.numberOfTouches;
907   pan.screenPosition = panEvent.currentPosition;
908   pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
909   pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
910   pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
911
912   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
913   while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
914   {
915     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
916     if(control)
917     {
918       Vector2 localCurrent;
919       control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
920       pan.position = localCurrent;
921
922       Vector2 localPrevious;
923       control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
924
925       pan.displacement = localCurrent - localPrevious;
926       pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
927       pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
928
929       handled = control.GetImplementation().OnAccessibilityPan(pan);
930     }
931
932     // If the gesture is not handled by the control, check its parent
933     if(!handled)
934     {
935       mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
936
937       if(!mCurrentGesturedActor)
938       {
939         DALI_LOG_ERROR("no more gestured actor");
940       }
941     }
942     else
943     {
944       // If handled, then update the pan gesture properties
945       PanGestureDetector::SetPanGestureProperties( pan );
946     }
947   }
948
949   return handled;
950 }
951
952 Toolkit::FocusManager::FocusChangedSignalType& FocusManager::FocusChangedSignal()
953 {
954   return mFocusChangedSignal;
955 }
956
957 Toolkit::FocusManager::FocusOvershotSignalType& FocusManager::FocusOvershotSignal()
958 {
959   return mFocusOvershotSignal;
960 }
961
962 Toolkit::FocusManager::FocusedActorActivatedSignalType& FocusManager::FocusedActorActivatedSignal()
963 {
964   return mFocusedActorActivatedSignal;
965 }
966
967 bool FocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
968 {
969   Dali::BaseHandle handle( object );
970
971   bool connected( true );
972   FocusManager* manager = dynamic_cast<FocusManager*>(object);
973
974   if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_CHANGED == signalName )
975   {
976     manager->FocusChangedSignal().Connect( tracker, functor );
977   }
978   else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUS_OVERSHOT == signalName )
979   {
980     manager->FocusOvershotSignal().Connect( tracker, functor );
981   }
982   else if( Dali::Toolkit::FocusManager::SIGNAL_FOCUSED_ACTOR_ACTIVATED== signalName )
983   {
984     manager->FocusedActorActivatedSignal().Connect( tracker, functor );
985   }
986   else
987   {
988     // signalName does not match any signal
989     connected = false;
990   }
991
992   return connected;
993 }
994
995 } // namespace Internal
996
997 } // namespace Toolkit
998
999 } // namespace Dali