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