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