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