Text cleaning.
[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
35 namespace Dali
36 {
37
38 namespace Toolkit
39 {
40
41 namespace Internal
42 {
43
44 namespace // unnamed namespace
45 {
46
47 // Signals
48
49 const char* const SIGNAL_FOCUS_CHANGED =           "focusChanged";
50 const char* const SIGNAL_FOCUS_OVERSHOT =          "focusOvershot";
51 const char* const SIGNAL_FOCUSED_ACTOR_ACTIVATED = "focusedActorActivated";
52
53 #if defined(DEBUG_ENABLED)
54 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FOCUS_MANAGER");
55 #endif
56
57 const char* const ACTOR_FOCUSABLE("focusable");
58 const char* const IS_FOCUS_GROUP("isFocusGroup");
59
60 const char* FOCUS_BORDER_IMAGE_PATH = DALI_IMAGE_DIR "B16-8_TTS_focus.png";
61 const Vector4 FOCUS_BORDER_IMAGE_BORDER = Vector4(7.0f, 7.0f, 7.0f, 7.0f);
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   Image borderImage = ResourceImage::New(FOCUS_BORDER_IMAGE_PATH);
667
668   ImageActor focusIndicator = ImageActor::New(borderImage);
669   focusIndicator.SetPositionInheritanceMode( Dali::USE_PARENT_POSITION_PLUS_LOCAL_POSITION );
670   focusIndicator.SetStyle( ImageActor::STYLE_NINE_PATCH );
671   focusIndicator.SetNinePatchBorder(FOCUS_BORDER_IMAGE_BORDER);
672   focusIndicator.SetPosition(Vector3(0.0f, 0.0f, 1.0f));
673
674   // Apply size constraint to the focus indicator
675   focusIndicator.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
676
677   SetFocusIndicatorActor(focusIndicator);
678 }
679
680 bool AccessibilityManager::ChangeAccessibilityStatus()
681 {
682   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
683   mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
684   Dali::Toolkit::AccessibilityManager handle( this );
685
686   if(mIsAccessibilityTtsEnabled)
687   {
688     // Show indicator when tts turned on if there is focused actor.
689     Actor actor = GetCurrentFocusActor();
690     if(actor)
691     {
692       if(mFocusIndicatorActor)
693       {
694         actor.Add(mFocusIndicatorActor);
695       }
696     }
697     mIsFocusIndicatorEnabled = true;
698
699     // Connect a signal to the TTS player to implement continuous reading mode.
700     Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
701     player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
702     mTtsCreated = true;
703   }
704   else
705   {
706     // Hide indicator when tts turned off
707     Actor actor = GetCurrentFocusActor();
708     if(actor)
709     {
710       actor.Remove(mFocusIndicatorActor);
711     }
712     mIsFocusIndicatorEnabled = false;
713
714     if( mTtsCreated )
715     {
716       // Disconnect the TTS state change signal.
717       Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
718       player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
719       mTtsCreated = true;
720     }
721   }
722
723   mStatusChangedSignal.Emit( handle );
724
725   return true;
726 }
727
728 bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
729 {
730   Dali::Toolkit::AccessibilityManager handle( this );
731   if( !mActionNextSignal.Empty() )
732   {
733     mActionNextSignal.Emit( handle );
734   }
735
736   if(mIsAccessibilityTtsEnabled)
737   {
738     mIsEndcapFeedbackEnabled = allowEndFeedback;
739     return MoveFocusForward();
740   }
741   else
742   {
743     return false;
744   }
745 }
746
747 bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
748 {
749   Dali::Toolkit::AccessibilityManager handle( this );
750   if( !mActionPreviousSignal.Empty() )
751   {
752     mActionPreviousSignal.Emit( handle );
753   }
754
755   if(mIsAccessibilityTtsEnabled)
756   {
757     mIsEndcapFeedbackEnabled = allowEndFeedback;
758     return MoveFocusBackward();
759   }
760   else
761   {
762     return false;
763   }
764 }
765
766 bool AccessibilityManager::AccessibilityActionActivate()
767 {
768   Dali::Toolkit::AccessibilityManager handle( this );
769   if( !mActionActivateSignal.Empty() )
770   {
771     mActionActivateSignal.Emit( handle );
772   }
773
774   bool ret = false;
775
776   Actor actor = GetCurrentFocusActor();
777   if(actor)
778   {
779     DoActivate(actor);
780     ret = true;
781   }
782
783   return ret;
784 }
785
786 bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
787 {
788   Dali::Toolkit::AccessibilityManager handle( this );
789
790   if( allowReadAgain )
791   {
792     if ( !mActionReadSignal.Empty() )
793     {
794       mActionReadSignal.Emit( handle );
795     }
796   }
797   else
798   {
799     if ( !mActionOverSignal.Empty() )
800     {
801       mActionOverSignal.Emit( handle );
802     }
803   }
804
805   bool ret = false;
806
807   if(mIsAccessibilityTtsEnabled)
808   {
809     // Find the focusable actor at the read position
810     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
811     Dali::HitTestAlgorithm::Results results;
812     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
813
814     FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
815     if(focusIDIter != mFocusIDContainer.end())
816     {
817       if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
818       {
819         // Move the focus to the actor
820         ret = SetCurrentFocusActor(results.actor);
821         DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
822       }
823     }
824   }
825
826   return ret;
827 }
828
829 bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
830 {
831   Dali::Toolkit::AccessibilityManager handle( this );
832   if( !mActionReadNextSignal.Empty() )
833   {
834     mActionReadNextSignal.Emit( handle );
835   }
836
837   if(mIsAccessibilityTtsEnabled)
838   {
839     return MoveFocusForward();
840   }
841   else
842   {
843     return false;
844   }
845 }
846
847 bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
848 {
849   Dali::Toolkit::AccessibilityManager handle( this );
850   if( !mActionReadPreviousSignal.Empty() )
851   {
852     mActionReadPreviousSignal.Emit( handle );
853   }
854
855   if(mIsAccessibilityTtsEnabled)
856   {
857     return MoveFocusBackward();
858   }
859   else
860   {
861     return false;
862   }
863 }
864
865 bool AccessibilityManager::AccessibilityActionUp()
866 {
867   Dali::Toolkit::AccessibilityManager handle( this );
868   if( !mActionUpSignal.Empty() )
869   {
870     mActionUpSignal.Emit( handle );
871   }
872
873   bool ret = false;
874
875   if(mIsAccessibilityTtsEnabled)
876   {
877     Actor actor = GetCurrentFocusActor();
878     if(actor)
879     {
880       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
881       if(control)
882       {
883         // Notify the control that it is activated
884         ret = GetImplementation( control ).OnAccessibilityValueChange(true);
885       }
886     }
887   }
888
889   return ret;
890 }
891
892 bool AccessibilityManager::AccessibilityActionDown()
893 {
894   Dali::Toolkit::AccessibilityManager handle( this );
895   if( !mActionDownSignal.Empty() )
896   {
897     mActionDownSignal.Emit( handle );
898   }
899
900   bool ret = false;
901
902   if(mIsAccessibilityTtsEnabled)
903   {
904     Actor actor = GetCurrentFocusActor();
905     if(actor)
906     {
907       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
908       if(control)
909       {
910         // Notify the control that it is activated
911         ret = GetImplementation( control ).OnAccessibilityValueChange(false);
912       }
913     }
914   }
915
916   return ret;
917 }
918
919 bool AccessibilityManager::ClearAccessibilityFocus()
920 {
921   Dali::Toolkit::AccessibilityManager handle( this );
922   if( !mActionClearFocusSignal.Empty() )
923   {
924     mActionClearFocusSignal.Emit( handle );
925   }
926
927   if(mIsAccessibilityTtsEnabled)
928   {
929     ClearFocus();
930     return true;
931   }
932   else
933   {
934     return false;
935   }
936 }
937
938 bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touchEvent )
939 {
940   Dali::Toolkit::AccessibilityManager handle( this );
941   if( !mActionScrollSignal.Empty() )
942   {
943     mActionScrollSignal.Emit( handle, touchEvent );
944   }
945
946   return true;
947 }
948
949 bool AccessibilityManager::AccessibilityActionBack()
950 {
951   Dali::Toolkit::AccessibilityManager handle( this );
952   if( !mActionBackSignal.Empty() )
953   {
954     mActionBackSignal.Emit( handle );
955   }
956
957   // TODO: Back to previous view
958
959   return mIsAccessibilityTtsEnabled;
960 }
961
962 bool AccessibilityManager::AccessibilityActionScrollUp()
963 {
964   Dali::Toolkit::AccessibilityManager handle( this );
965   if( !mActionScrollUpSignal.Empty() )
966   {
967     mActionScrollUpSignal.Emit( handle );
968   }
969
970   bool ret = false;
971
972   if(mIsAccessibilityTtsEnabled)
973   {
974     Actor actor = GetCurrentFocusActor();
975     if(actor)
976     {
977       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
978       if(control)
979       {
980         // TODO: Notify the control to scroll up. Should control handle this?
981 //        ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
982       }
983     }
984   }
985
986   return ret;
987 }
988
989 bool AccessibilityManager::AccessibilityActionScrollDown()
990 {
991   Dali::Toolkit::AccessibilityManager handle( this );
992   if( !mActionScrollDownSignal.Empty() )
993   {
994     mActionScrollDownSignal.Emit( handle );
995   }
996
997   bool ret = false;
998
999   if(mIsAccessibilityTtsEnabled)
1000   {
1001     Actor actor = GetCurrentFocusActor();
1002     if(actor)
1003     {
1004       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1005       if(control)
1006       {
1007         // TODO: Notify the control to scroll down. Should control handle this?
1008 //        ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
1009       }
1010     }
1011   }
1012
1013   return ret;
1014 }
1015
1016 bool AccessibilityManager::AccessibilityActionPageLeft()
1017 {
1018   Dali::Toolkit::AccessibilityManager handle( this );
1019   if( !mActionPageLeftSignal.Empty() )
1020   {
1021     mActionPageLeftSignal.Emit( handle );
1022   }
1023
1024   bool ret = false;
1025
1026   if(mIsAccessibilityTtsEnabled)
1027   {
1028     Actor actor = GetCurrentFocusActor();
1029     if(actor)
1030     {
1031       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1032       if(control)
1033       {
1034         // TODO: Notify the control to scroll left to the previous page. Should control handle this?
1035 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
1036       }
1037     }
1038   }
1039
1040   return ret;
1041 }
1042
1043 bool AccessibilityManager::AccessibilityActionPageRight()
1044 {
1045   Dali::Toolkit::AccessibilityManager handle( this );
1046   if( !mActionPageRightSignal.Empty() )
1047   {
1048     mActionPageRightSignal.Emit( handle );
1049   }
1050
1051   bool ret = false;
1052
1053   if(mIsAccessibilityTtsEnabled)
1054   {
1055     Actor actor = GetCurrentFocusActor();
1056     if(actor)
1057     {
1058       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1059       if(control)
1060       {
1061         // TODO: Notify the control to scroll right to the next page. Should control handle this?
1062 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
1063       }
1064     }
1065   }
1066
1067   return ret;
1068 }
1069
1070 bool AccessibilityManager::AccessibilityActionPageUp()
1071 {
1072   Dali::Toolkit::AccessibilityManager handle( this );
1073   if( !mActionPageUpSignal.Empty() )
1074   {
1075     mActionPageUpSignal.Emit( handle );
1076   }
1077
1078   bool ret = false;
1079
1080   if(mIsAccessibilityTtsEnabled)
1081   {
1082     Actor actor = GetCurrentFocusActor();
1083     if(actor)
1084     {
1085       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1086       if(control)
1087       {
1088         // TODO: Notify the control to scroll up to the previous page. Should control handle this?
1089 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
1090       }
1091     }
1092   }
1093
1094   return ret;
1095 }
1096
1097 bool AccessibilityManager::AccessibilityActionPageDown()
1098 {
1099   Dali::Toolkit::AccessibilityManager handle( this );
1100   if( !mActionPageDownSignal.Empty() )
1101   {
1102     mActionPageDownSignal.Emit( handle );
1103   }
1104
1105   bool ret = false;
1106
1107   if(mIsAccessibilityTtsEnabled)
1108   {
1109     Actor actor = GetCurrentFocusActor();
1110     if(actor)
1111     {
1112       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1113       if(control)
1114       {
1115         // TODO: Notify the control to scroll down to the next page. Should control handle this?
1116 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
1117       }
1118     }
1119   }
1120
1121   return ret;
1122 }
1123
1124 bool AccessibilityManager::AccessibilityActionMoveToFirst()
1125 {
1126   Dali::Toolkit::AccessibilityManager handle( this );
1127   if( !mActionMoveToFirstSignal.Empty() )
1128   {
1129     mActionMoveToFirstSignal.Emit( handle );
1130   }
1131
1132   // TODO: Move to the first item on screen
1133
1134   return mIsAccessibilityTtsEnabled;
1135 }
1136
1137 bool AccessibilityManager::AccessibilityActionMoveToLast()
1138 {
1139   Dali::Toolkit::AccessibilityManager handle( this );
1140   if( !mActionMoveToLastSignal.Empty() )
1141   {
1142     mActionMoveToLastSignal.Emit( handle );
1143   }
1144
1145   // TODO: Move to the last item on screen
1146
1147   return mIsAccessibilityTtsEnabled;
1148 }
1149
1150 bool AccessibilityManager::AccessibilityActionReadFromTop()
1151 {
1152   Dali::Toolkit::AccessibilityManager handle( this );
1153   if( !mActionReadFromTopSignal.Empty() )
1154   {
1155     mActionReadFromTopSignal.Emit( handle );
1156   }
1157
1158   // TODO: Move to the top item on screen and read from the item continuously
1159
1160   return mIsAccessibilityTtsEnabled;
1161 }
1162
1163 bool AccessibilityManager::AccessibilityActionReadFromNext()
1164 {
1165   Dali::Toolkit::AccessibilityManager handle( this );
1166
1167   if( !mActionReadFromNextSignal.Empty() )
1168   {
1169     mActionReadFromNextSignal.Emit( handle );
1170   }
1171
1172   if( mIsAccessibilityTtsEnabled )
1173   {
1174     // Mark that we are in continuous play mode, so TTS signals can move focus.
1175     mContinuousPlayMode = true;
1176
1177     // Attempt to move to the next item and read from the item continuously.
1178     MoveFocusForward();
1179   }
1180
1181   return mIsAccessibilityTtsEnabled;
1182 }
1183
1184 void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
1185 {
1186   if( mContinuousPlayMode )
1187   {
1188     // If we were playing and now we have stopped, attempt to play the next item.
1189     if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
1190     {
1191       // Attempt to move the focus forward and play.
1192       // If we can't cancel continuous play mode.
1193       if( !MoveFocusForward() )
1194       {
1195         // We are done, exit continuous play mode.
1196         mContinuousPlayMode = false;
1197       }
1198     }
1199     else
1200     {
1201       // Unexpected play state change, exit continuous play mode.
1202       mContinuousPlayMode = false;
1203     }
1204   }
1205 }
1206
1207 bool AccessibilityManager::AccessibilityActionZoom()
1208 {
1209   Dali::Toolkit::AccessibilityManager handle( this );
1210   if( !mActionZoomSignal.Empty() )
1211   {
1212     mActionZoomSignal.Emit( handle );
1213   }
1214
1215   bool ret = false;
1216
1217   if(mIsAccessibilityTtsEnabled)
1218   {
1219     Actor actor = GetCurrentFocusActor();
1220     if(actor)
1221     {
1222       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1223       if(control)
1224       {
1225         // Notify the control to zoom
1226         ret = GetImplementation( control ).OnAccessibilityZoom();
1227       }
1228     }
1229   }
1230
1231   return ret;
1232 }
1233
1234 bool AccessibilityManager::AccessibilityActionReadIndicatorInformation()
1235 {
1236   Dali::Toolkit::AccessibilityManager handle( this );
1237   if( !mActionReadIndicatorInformationSignal.Empty() )
1238   {
1239     mActionReadIndicatorInformationSignal.Emit( handle );
1240   }
1241
1242   // TODO: Read the information in the indicator
1243
1244   return mIsAccessibilityTtsEnabled;
1245 }
1246
1247 bool AccessibilityManager::AccessibilityActionReadPauseResume()
1248 {
1249   Dali::Toolkit::AccessibilityManager handle( this );
1250   if( !mActionReadPauseResumeSignal.Empty() )
1251   {
1252     mActionReadPauseResumeSignal.Emit( handle );
1253   }
1254
1255   bool ret = false;
1256
1257   if(mIsAccessibilityTtsEnabled)
1258   {
1259     // Pause or resume the TTS player
1260     Dali::TtsPlayer player = Dali::TtsPlayer::Get(Dali::TtsPlayer::SCREEN_READER);
1261     Dali::TtsPlayer::State state = player.GetState();
1262     if(state == Dali::TtsPlayer::PLAYING)
1263     {
1264       player.Pause();
1265       ret = true;
1266     }
1267     else if(state == Dali::TtsPlayer::PAUSED)
1268     {
1269       player.Resume();
1270       ret = true;
1271     }
1272   }
1273
1274   return ret;
1275 }
1276
1277 bool AccessibilityManager::AccessibilityActionStartStop()
1278 {
1279   Dali::Toolkit::AccessibilityManager handle( this );
1280   if( !mActionStartStopSignal.Empty() )
1281   {
1282     mActionStartStopSignal.Emit( handle );
1283   }
1284
1285   // TODO: Start/stop the current action
1286
1287   return mIsAccessibilityTtsEnabled;
1288 }
1289
1290 bool AccessibilityManager::AccessibilityActionTouch(const TouchEvent& touchEvent)
1291 {
1292   bool handled = false;
1293
1294   // TODO: Need to convert the touchevent for the focused actor?
1295
1296   Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(GetCurrentFocusActor());
1297   if(control)
1298   {
1299     handled = GetImplementation( control ).OnAccessibilityTouch(touchEvent);
1300   }
1301
1302   return handled;
1303 }
1304
1305 bool AccessibilityManager::HandlePanGesture(const Integration::PanGestureEvent& panEvent)
1306 {
1307   bool handled = false;
1308
1309   if( panEvent.state == Gesture::Started )
1310   {
1311     // Find the focusable actor at the event position
1312     Dali::HitTestAlgorithm::Results results;
1313     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
1314
1315     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), panEvent.currentPosition, results, IsActorFocusableFunction );
1316     mCurrentGesturedActor = results.actor;
1317
1318     if(!mCurrentGesturedActor)
1319     {
1320       DALI_LOG_ERROR("Gesture detected, but no hit actor");
1321     }
1322   }
1323
1324   // Gesture::Finished (Up) events are delivered with previous (Motion) event position
1325   // Use the real previous position; otherwise we may incorrectly get a ZERO velocity
1326   if ( Gesture::Finished != panEvent.state )
1327   {
1328     // Store the previous position for next Gesture::Finished iteration.
1329     mPreviousPosition = panEvent.previousPosition;
1330   }
1331
1332   Actor rootActor = Stage::GetCurrent().GetRootLayer();
1333
1334   Dali::PanGesture pan(panEvent.state);
1335   pan.time = panEvent.time;
1336   pan.numberOfTouches = panEvent.numberOfTouches;
1337   pan.screenPosition = panEvent.currentPosition;
1338   pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
1339   pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
1340   pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
1341
1342   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
1343   while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
1344   {
1345     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
1346     if(control)
1347     {
1348       Vector2 localCurrent;
1349       control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
1350       pan.position = localCurrent;
1351
1352       Vector2 localPrevious;
1353       control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
1354
1355       pan.displacement = localCurrent - localPrevious;
1356       pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
1357       pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
1358
1359       handled = GetImplementation( control ).OnAccessibilityPan(pan);
1360     }
1361
1362     // If the gesture is not handled by the control, check its parent
1363     if(!handled)
1364     {
1365       mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
1366
1367       if(!mCurrentGesturedActor)
1368       {
1369         DALI_LOG_ERROR("no more gestured actor");
1370       }
1371     }
1372     else
1373     {
1374       // If handled, then update the pan gesture properties
1375       PanGestureDetector::SetPanGestureProperties( pan );
1376     }
1377   }
1378
1379   return handled;
1380 }
1381
1382 Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
1383 {
1384   return mFocusChangedSignal;
1385 }
1386
1387 Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
1388 {
1389   return mFocusOvershotSignal;
1390 }
1391
1392 Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
1393 {
1394   return mFocusedActorActivatedSignal;
1395 }
1396
1397 bool AccessibilityManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1398 {
1399   Dali::BaseHandle handle( object );
1400
1401   bool connected( true );
1402   AccessibilityManager* manager = dynamic_cast<AccessibilityManager*>( object );
1403
1404   if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
1405   {
1406     manager->FocusChangedSignal().Connect( tracker, functor );
1407   }
1408   else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_OVERSHOT ) )
1409   {
1410     manager->FocusOvershotSignal().Connect( tracker, functor );
1411   }
1412   else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ACTIVATED ) )
1413   {
1414     manager->FocusedActorActivatedSignal().Connect( tracker, functor );
1415   }
1416   else
1417   {
1418     // signalName does not match any signal
1419     connected = false;
1420   }
1421
1422   return connected;
1423 }
1424
1425 } // namespace Internal
1426
1427 } // namespace Toolkit
1428
1429 } // namespace Dali