[dali_1.9.5] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / accessibility-manager / accessibility-manager-impl.cpp
1 /*
2  * Copyright (c) 2019 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   mCurrentGesturedActor(),
112   mFocusIndicatorActor(),
113   mPreviousPosition( 0.0f, 0.0f ),
114   mRecursiveFocusMoveCounter(0),
115   mIsWrapped(false),
116   mIsFocusWithinGroup(false),
117   mIsEndcapFeedbackEnabled(false),
118   mIsEndcapFeedbackPlayed(false),
119   mIsAccessibilityTtsEnabled(false),
120   mTtsCreated(false),
121   mIsFocusIndicatorEnabled(false),
122   mContinuousPlayMode(false)
123 {
124 }
125
126 AccessibilityManager::~AccessibilityManager()
127 {
128 }
129
130 void AccessibilityManager::Initialise()
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 )
345       {
346         actor.Add( GetFocusIndicatorActor() );
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 && mFocusIndicatorActor )
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   if( mFocusIndicatorActor != indicator )
573   {
574     Actor currentFocusActor = GetCurrentFocusActor();
575     if( currentFocusActor )
576     {
577       // The new focus indicator should be added to the current focused actor immediately
578       if( mFocusIndicatorActor )
579       {
580         currentFocusActor.Remove( mFocusIndicatorActor );
581       }
582
583       if( indicator )
584       {
585         currentFocusActor.Add( indicator );
586       }
587     }
588
589     mFocusIndicatorActor = indicator;
590   }
591 }
592
593 Actor AccessibilityManager::GetFocusIndicatorActor()
594 {
595   if( ! mFocusIndicatorActor )
596   {
597     // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
598     mFocusIndicatorActor = Toolkit::ImageView::New( FOCUS_BORDER_IMAGE_PATH );
599     mFocusIndicatorActor.SetParentOrigin( ParentOrigin::CENTER );
600     mFocusIndicatorActor.SetZ( 1.0f );
601
602     // Apply size constraint to the focus indicator
603     mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
604   }
605
606   return mFocusIndicatorActor;
607 }
608
609 bool AccessibilityManager::DoMoveFocus(FocusIDIter focusIDIter, bool forward, bool wrapped)
610 {
611   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] %d focusable actors\n", __FUNCTION__, __LINE__, mFocusIDContainer.size());
612   DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] focus order : %d\n", __FUNCTION__, __LINE__, (*focusIDIter).first);
613
614   if( (forward && ++focusIDIter == mFocusIDContainer.end())
615     || (!forward && focusIDIter-- == mFocusIDContainer.begin()) )
616   {
617     if(mIsEndcapFeedbackEnabled)
618     {
619       if(mIsEndcapFeedbackPlayed == false)
620       {
621         // play sound & skip moving once
622         Dali::SoundPlayer soundPlayer = Dali::SoundPlayer::Get();
623         if(soundPlayer)
624         {
625           soundPlayer.PlaySound(FOCUS_CHAIN_END_SOUND_FILE);
626         }
627
628         mIsEndcapFeedbackPlayed = true;
629         return true;
630       }
631       mIsEndcapFeedbackPlayed = false;
632     }
633
634     if(wrapped)
635     {
636       if(forward)
637       {
638         focusIDIter = mFocusIDContainer.begin();
639       }
640       else
641       {
642         focusIDIter = mFocusIDContainer.end();
643         --focusIDIter;//We want forward iterator to the last element here
644       }
645     }
646     else
647     {
648       DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Overshot\n", __FUNCTION__, __LINE__);
649       // Send notification for handling overshooted situation
650       mFocusOvershotSignal.Emit(GetCurrentFocusActor(), forward ? Toolkit::AccessibilityManager::OVERSHOT_NEXT : Toolkit::AccessibilityManager::OVERSHOT_PREVIOUS);
651
652       return false; // Try to move the focus out of the scope
653     }
654   }
655
656   // Invalid focus.
657   if( focusIDIter == mFocusIDContainer.end() )
658   {
659     return false;
660   }
661
662   // Note: This function performs the focus change.
663   if( !DoSetCurrentFocusActor( (*focusIDIter).second ) )
664   {
665     mRecursiveFocusMoveCounter++;
666     if(mRecursiveFocusMoveCounter > mFocusIDContainer.size())
667     {
668       // We've attempted to focus all the actors in the whole focus chain and no actor
669       // can be focused successfully.
670       DALI_LOG_WARNING("[%s] There is no more focusable actor in %d focus chains\n", __FUNCTION__, mRecursiveFocusMoveCounter);
671
672       return false;
673     }
674     else
675     {
676       return DoMoveFocus(focusIDIter, forward, wrapped);
677     }
678   }
679
680   return true;
681 }
682
683 void AccessibilityManager::SetFocusable(Actor actor, bool focusable)
684 {
685   if(actor)
686   {
687     // Create/Set actor focusable property.
688     actor.RegisterProperty( ACTOR_FOCUSABLE, focusable, Property::READ_WRITE );
689   }
690 }
691
692 bool AccessibilityManager::ChangeAccessibilityStatus()
693 {
694   AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
695   mIsAccessibilityTtsEnabled = adaptor.IsEnabled();
696   Dali::Toolkit::AccessibilityManager handle( this );
697
698   if(mIsAccessibilityTtsEnabled)
699   {
700     // Show indicator when tts turned on if there is focused actor.
701     Actor actor = GetCurrentFocusActor();
702     if(actor)
703     {
704       actor.Add( GetFocusIndicatorActor() );
705     }
706     mIsFocusIndicatorEnabled = true;
707
708     // Connect a signal to the TTS player to implement continuous reading mode.
709     Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
710     player.StateChangedSignal().Connect( this, &AccessibilityManager::TtsStateChanged );
711     mTtsCreated = true;
712   }
713   else
714   {
715     // Hide indicator when tts turned off
716     Actor actor = GetCurrentFocusActor();
717     if( actor && mFocusIndicatorActor )
718     {
719       actor.Remove( mFocusIndicatorActor );
720     }
721     mIsFocusIndicatorEnabled = false;
722
723     if( mTtsCreated )
724     {
725       // Disconnect the TTS state change signal.
726       Dali::TtsPlayer player = Dali::TtsPlayer::Get( Dali::TtsPlayer::SCREEN_READER );
727       player.StateChangedSignal().Disconnect( this, &AccessibilityManager::TtsStateChanged );
728       mTtsCreated = true;
729     }
730   }
731
732   mStatusChangedSignal.Emit( handle );
733
734   return true;
735 }
736
737 bool AccessibilityManager::AccessibilityActionNext(bool allowEndFeedback)
738 {
739   Dali::Toolkit::AccessibilityManager handle( this );
740   if( !mActionNextSignal.Empty() )
741   {
742     mActionNextSignal.Emit( handle );
743   }
744
745   if(mIsAccessibilityTtsEnabled)
746   {
747     mIsEndcapFeedbackEnabled = allowEndFeedback;
748     return MoveFocusForward();
749   }
750   else
751   {
752     return false;
753   }
754 }
755
756 bool AccessibilityManager::AccessibilityActionPrevious(bool allowEndFeedback)
757 {
758   Dali::Toolkit::AccessibilityManager handle( this );
759   if( !mActionPreviousSignal.Empty() )
760   {
761     mActionPreviousSignal.Emit( handle );
762   }
763
764   if(mIsAccessibilityTtsEnabled)
765   {
766     mIsEndcapFeedbackEnabled = allowEndFeedback;
767     return MoveFocusBackward();
768   }
769   else
770   {
771     return false;
772   }
773 }
774
775 bool AccessibilityManager::AccessibilityActionActivate()
776 {
777   Dali::Toolkit::AccessibilityManager handle( this );
778   if( !mActionActivateSignal.Empty() )
779   {
780     mActionActivateSignal.Emit( handle );
781   }
782
783   bool ret = false;
784
785   Actor actor = GetCurrentFocusActor();
786   if(actor)
787   {
788     DoActivate(actor);
789     ret = true;
790   }
791
792   return ret;
793 }
794
795 bool AccessibilityManager::AccessibilityActionRead(bool allowReadAgain)
796 {
797   Dali::Toolkit::AccessibilityManager handle( this );
798
799   if( allowReadAgain )
800   {
801     if ( !mActionReadSignal.Empty() )
802     {
803       mActionReadSignal.Emit( handle );
804     }
805   }
806   else
807   {
808     if ( !mActionOverSignal.Empty() )
809     {
810       mActionOverSignal.Emit( handle );
811     }
812   }
813
814   bool ret = false;
815
816   if(mIsAccessibilityTtsEnabled)
817   {
818     // Find the focusable actor at the read position
819     AccessibilityAdaptor adaptor = AccessibilityAdaptor::Get();
820     Dali::HitTestAlgorithm::Results results;
821     Dali::HitTestAlgorithm::HitTest( Stage::GetCurrent(), adaptor.GetReadPosition(), results, IsActorFocusableFunction );
822
823     FocusIDIter focusIDIter = mFocusIDContainer.find(GetFocusOrder(results.actor));
824     if(focusIDIter != mFocusIDContainer.end())
825     {
826       if( allowReadAgain || (results.actor != GetCurrentFocusActor()) )
827       {
828         // Move the focus to the actor
829         ret = SetCurrentFocusActor(results.actor);
830         DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SetCurrentFocusActor returns %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
831       }
832     }
833   }
834
835   return ret;
836 }
837
838 bool AccessibilityManager::AccessibilityActionReadNext(bool allowEndFeedback)
839 {
840   Dali::Toolkit::AccessibilityManager handle( this );
841   if( !mActionReadNextSignal.Empty() )
842   {
843     mActionReadNextSignal.Emit( handle );
844   }
845
846   if(mIsAccessibilityTtsEnabled)
847   {
848     return MoveFocusForward();
849   }
850   else
851   {
852     return false;
853   }
854 }
855
856 bool AccessibilityManager::AccessibilityActionReadPrevious(bool allowEndFeedback)
857 {
858   Dali::Toolkit::AccessibilityManager handle( this );
859   if( !mActionReadPreviousSignal.Empty() )
860   {
861     mActionReadPreviousSignal.Emit( handle );
862   }
863
864   if(mIsAccessibilityTtsEnabled)
865   {
866     return MoveFocusBackward();
867   }
868   else
869   {
870     return false;
871   }
872 }
873
874 bool AccessibilityManager::AccessibilityActionUp()
875 {
876   Dali::Toolkit::AccessibilityManager handle( this );
877   if( !mActionUpSignal.Empty() )
878   {
879     mActionUpSignal.Emit( handle );
880   }
881
882   bool ret = false;
883
884   if(mIsAccessibilityTtsEnabled)
885   {
886     Actor actor = GetCurrentFocusActor();
887     if(actor)
888     {
889       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
890       if(control)
891       {
892         // Notify the control that it is activated
893         ret = GetImplementation( control ).OnAccessibilityValueChange(true);
894       }
895     }
896   }
897
898   return ret;
899 }
900
901 bool AccessibilityManager::AccessibilityActionDown()
902 {
903   Dali::Toolkit::AccessibilityManager handle( this );
904   if( !mActionDownSignal.Empty() )
905   {
906     mActionDownSignal.Emit( handle );
907   }
908
909   bool ret = false;
910
911   if(mIsAccessibilityTtsEnabled)
912   {
913     Actor actor = GetCurrentFocusActor();
914     if(actor)
915     {
916       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
917       if(control)
918       {
919         // Notify the control that it is activated
920         ret = GetImplementation( control ).OnAccessibilityValueChange(false);
921       }
922     }
923   }
924
925   return ret;
926 }
927
928 bool AccessibilityManager::ClearAccessibilityFocus()
929 {
930   Dali::Toolkit::AccessibilityManager handle( this );
931   if( !mActionClearFocusSignal.Empty() )
932   {
933     mActionClearFocusSignal.Emit( handle );
934   }
935
936   if(mIsAccessibilityTtsEnabled)
937   {
938     ClearFocus();
939     return true;
940   }
941   else
942   {
943     return false;
944   }
945 }
946
947 bool AccessibilityManager::AccessibilityActionScroll( Dali::TouchEvent& touchEvent )
948 {
949   Dali::Toolkit::AccessibilityManager handle( this );
950   if( !mActionScrollSignal.Empty() )
951   {
952     mActionScrollSignal.Emit( handle, touchEvent );
953   }
954
955   return true;
956 }
957
958 bool AccessibilityManager::AccessibilityActionBack()
959 {
960   Dali::Toolkit::AccessibilityManager handle( this );
961   if( !mActionBackSignal.Empty() )
962   {
963     mActionBackSignal.Emit( handle );
964   }
965
966   // TODO: Back to previous view
967
968   return mIsAccessibilityTtsEnabled;
969 }
970
971 bool AccessibilityManager::AccessibilityActionScrollUp()
972 {
973   Dali::Toolkit::AccessibilityManager handle( this );
974   if( !mActionScrollUpSignal.Empty() )
975   {
976     mActionScrollUpSignal.Emit( handle );
977   }
978
979   bool ret = false;
980
981   if(mIsAccessibilityTtsEnabled)
982   {
983     Actor actor = GetCurrentFocusActor();
984     if(actor)
985     {
986       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
987       if(control)
988       {
989         // TODO: Notify the control to scroll up. Should control handle this?
990 //        ret = GetImplementation( control ).OnAccessibilityScroll(Direction::UP);
991       }
992     }
993   }
994
995   return ret;
996 }
997
998 bool AccessibilityManager::AccessibilityActionScrollDown()
999 {
1000   Dali::Toolkit::AccessibilityManager handle( this );
1001   if( !mActionScrollDownSignal.Empty() )
1002   {
1003     mActionScrollDownSignal.Emit( handle );
1004   }
1005
1006   bool ret = false;
1007
1008   if(mIsAccessibilityTtsEnabled)
1009   {
1010     Actor actor = GetCurrentFocusActor();
1011     if(actor)
1012     {
1013       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1014       if(control)
1015       {
1016         // TODO: Notify the control to scroll down. Should control handle this?
1017 //        ret = GetImplementation( control ).OnAccessibilityScrollDown(Direction::DOWN);
1018       }
1019     }
1020   }
1021
1022   return ret;
1023 }
1024
1025 bool AccessibilityManager::AccessibilityActionPageLeft()
1026 {
1027   Dali::Toolkit::AccessibilityManager handle( this );
1028   if( !mActionPageLeftSignal.Empty() )
1029   {
1030     mActionPageLeftSignal.Emit( handle );
1031   }
1032
1033   bool ret = false;
1034
1035   if(mIsAccessibilityTtsEnabled)
1036   {
1037     Actor actor = GetCurrentFocusActor();
1038     if(actor)
1039     {
1040       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1041       if(control)
1042       {
1043         // TODO: Notify the control to scroll left to the previous page. Should control handle this?
1044 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::LEFT);
1045       }
1046     }
1047   }
1048
1049   return ret;
1050 }
1051
1052 bool AccessibilityManager::AccessibilityActionPageRight()
1053 {
1054   Dali::Toolkit::AccessibilityManager handle( this );
1055   if( !mActionPageRightSignal.Empty() )
1056   {
1057     mActionPageRightSignal.Emit( handle );
1058   }
1059
1060   bool ret = false;
1061
1062   if(mIsAccessibilityTtsEnabled)
1063   {
1064     Actor actor = GetCurrentFocusActor();
1065     if(actor)
1066     {
1067       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1068       if(control)
1069       {
1070         // TODO: Notify the control to scroll right to the next page. Should control handle this?
1071 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::RIGHT);
1072       }
1073     }
1074   }
1075
1076   return ret;
1077 }
1078
1079 bool AccessibilityManager::AccessibilityActionPageUp()
1080 {
1081   Dali::Toolkit::AccessibilityManager handle( this );
1082   if( !mActionPageUpSignal.Empty() )
1083   {
1084     mActionPageUpSignal.Emit( handle );
1085   }
1086
1087   bool ret = false;
1088
1089   if(mIsAccessibilityTtsEnabled)
1090   {
1091     Actor actor = GetCurrentFocusActor();
1092     if(actor)
1093     {
1094       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1095       if(control)
1096       {
1097         // TODO: Notify the control to scroll up to the previous page. Should control handle this?
1098 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::UP);
1099       }
1100     }
1101   }
1102
1103   return ret;
1104 }
1105
1106 bool AccessibilityManager::AccessibilityActionPageDown()
1107 {
1108   Dali::Toolkit::AccessibilityManager handle( this );
1109   if( !mActionPageDownSignal.Empty() )
1110   {
1111     mActionPageDownSignal.Emit( handle );
1112   }
1113
1114   bool ret = false;
1115
1116   if(mIsAccessibilityTtsEnabled)
1117   {
1118     Actor actor = GetCurrentFocusActor();
1119     if(actor)
1120     {
1121       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1122       if(control)
1123       {
1124         // TODO: Notify the control to scroll down to the next page. Should control handle this?
1125 //        ret = GetImplementation( control ).OnAccessibilityScrollToPage(Direction::DOWN);
1126       }
1127     }
1128   }
1129
1130   return ret;
1131 }
1132
1133 bool AccessibilityManager::AccessibilityActionMoveToFirst()
1134 {
1135   Dali::Toolkit::AccessibilityManager handle( this );
1136   if( !mActionMoveToFirstSignal.Empty() )
1137   {
1138     mActionMoveToFirstSignal.Emit( handle );
1139   }
1140
1141   // TODO: Move to the first item on screen
1142
1143   return mIsAccessibilityTtsEnabled;
1144 }
1145
1146 bool AccessibilityManager::AccessibilityActionMoveToLast()
1147 {
1148   Dali::Toolkit::AccessibilityManager handle( this );
1149   if( !mActionMoveToLastSignal.Empty() )
1150   {
1151     mActionMoveToLastSignal.Emit( handle );
1152   }
1153
1154   // TODO: Move to the last item on screen
1155
1156   return mIsAccessibilityTtsEnabled;
1157 }
1158
1159 bool AccessibilityManager::AccessibilityActionReadFromTop()
1160 {
1161   Dali::Toolkit::AccessibilityManager handle( this );
1162   if( !mActionReadFromTopSignal.Empty() )
1163   {
1164     mActionReadFromTopSignal.Emit( handle );
1165   }
1166
1167   // TODO: Move to the top item on screen and read from the item continuously
1168
1169   return mIsAccessibilityTtsEnabled;
1170 }
1171
1172 bool AccessibilityManager::AccessibilityActionReadFromNext()
1173 {
1174   Dali::Toolkit::AccessibilityManager handle( this );
1175
1176   if( !mActionReadFromNextSignal.Empty() )
1177   {
1178     mActionReadFromNextSignal.Emit( handle );
1179   }
1180
1181   if( mIsAccessibilityTtsEnabled )
1182   {
1183     // Mark that we are in continuous play mode, so TTS signals can move focus.
1184     mContinuousPlayMode = true;
1185
1186     // Attempt to move to the next item and read from the item continuously.
1187     MoveFocusForward();
1188   }
1189
1190   return mIsAccessibilityTtsEnabled;
1191 }
1192
1193 void AccessibilityManager::TtsStateChanged( const Dali::TtsPlayer::State previousState, const Dali::TtsPlayer::State currentState )
1194 {
1195   if( mContinuousPlayMode )
1196   {
1197     // If we were playing and now we have stopped, attempt to play the next item.
1198     if( ( previousState == Dali::TtsPlayer::PLAYING ) && ( currentState == Dali::TtsPlayer::READY ) )
1199     {
1200       // Attempt to move the focus forward and play.
1201       // If we can't cancel continuous play mode.
1202       if( !MoveFocusForward() )
1203       {
1204         // We are done, exit continuous play mode.
1205         mContinuousPlayMode = false;
1206       }
1207     }
1208     else
1209     {
1210       // Unexpected play state change, exit continuous play mode.
1211       mContinuousPlayMode = false;
1212     }
1213   }
1214 }
1215
1216 bool AccessibilityManager::AccessibilityActionZoom()
1217 {
1218   Dali::Toolkit::AccessibilityManager handle( this );
1219   if( !mActionZoomSignal.Empty() )
1220   {
1221     mActionZoomSignal.Emit( handle );
1222   }
1223
1224   bool ret = false;
1225
1226   if(mIsAccessibilityTtsEnabled)
1227   {
1228     Actor actor = GetCurrentFocusActor();
1229     if(actor)
1230     {
1231       Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(actor);
1232       if(control)
1233       {
1234         // Notify the control to zoom
1235         ret = GetImplementation( control ).OnAccessibilityZoom();
1236       }
1237     }
1238   }
1239
1240   return ret;
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 AccessibilityGestureEvent& panEvent)
1302 {
1303   bool handled = false;
1304
1305   if( panEvent.state == AccessibilityGestureEvent::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\n");
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 ( AccessibilityGestureEvent::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( static_cast<Dali::Gesture::State>(panEvent.state) );
1331
1332   pan.time = panEvent.time;
1333   pan.numberOfTouches = panEvent.numberOfTouches;
1334   pan.screenPosition = panEvent.currentPosition;
1335   pan.screenDisplacement = mPreviousPosition - panEvent.currentPosition;
1336   pan.screenVelocity.x = pan.screenDisplacement.x / panEvent.timeDelta;
1337   pan.screenVelocity.y = pan.screenDisplacement.y / panEvent.timeDelta;
1338
1339   // Only handle the pan gesture when the current focused actor is scrollable or within a scrollable actor
1340   while(mCurrentGesturedActor && mCurrentGesturedActor != rootActor && !handled)
1341   {
1342     Dali::Toolkit::Control control = Dali::Toolkit::Control::DownCast(mCurrentGesturedActor);
1343     if(control)
1344     {
1345       Vector2 localCurrent;
1346       control.ScreenToLocal( localCurrent.x, localCurrent.y, panEvent.currentPosition.x, panEvent.currentPosition.y );
1347       pan.position = localCurrent;
1348
1349       Vector2 localPrevious;
1350       control.ScreenToLocal( localPrevious.x, localPrevious.y, mPreviousPosition.x, mPreviousPosition.y );
1351
1352       pan.displacement = localCurrent - localPrevious;
1353       pan.velocity.x = pan.displacement.x / panEvent.timeDelta;
1354       pan.velocity.y = pan.displacement.y / panEvent.timeDelta;
1355
1356       handled = GetImplementation( control ).OnAccessibilityPan(pan);
1357     }
1358
1359     // If the gesture is not handled by the control, check its parent
1360     if(!handled)
1361     {
1362       mCurrentGesturedActor = mCurrentGesturedActor.GetParent();
1363
1364       if(!mCurrentGesturedActor)
1365       {
1366         DALI_LOG_ERROR("no more gestured actor\n");
1367       }
1368     }
1369     else
1370     {
1371       // If handled, then update the pan gesture properties
1372       PanGestureDetector::SetPanGestureProperties( pan );
1373     }
1374   }
1375
1376   return handled;
1377 }
1378
1379 Toolkit::AccessibilityManager::FocusChangedSignalType& AccessibilityManager::FocusChangedSignal()
1380 {
1381   return mFocusChangedSignal;
1382 }
1383
1384 Toolkit::AccessibilityManager::FocusOvershotSignalType& AccessibilityManager::FocusOvershotSignal()
1385 {
1386   return mFocusOvershotSignal;
1387 }
1388
1389 Toolkit::AccessibilityManager::FocusedActorActivatedSignalType& AccessibilityManager::FocusedActorActivatedSignal()
1390 {
1391   return mFocusedActorActivatedSignal;
1392 }
1393
1394 } // namespace Internal
1395
1396 } // namespace Toolkit
1397
1398 } // namespace Dali