Changes after Stage moved to Devel API
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / focus-manager / keyboard-focus-manager-impl.cpp
1 /*
2  * Copyright (c) 2020 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 "keyboard-focus-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/common/singleton-service.h>
26 #include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
27 #include <dali/public-api/animation/constraints.h>
28 #include <dali/public-api/events/key-event.h>
29 #include <dali/public-api/events/touch-data.h>
30 #include <dali/public-api/object/type-registry.h>
31 #include <dali/public-api/object/type-registry-helper.h>
32 #include <dali/public-api/object/property-map.h>
33 #include <dali/integration-api/debug.h>
34 #include <dali/integration-api/adaptor-framework/adaptor.h>
35 #include <dali/integration-api/adaptor-framework/scene-holder.h>
36
37 // INTERNAL INCLUDES
38 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
39 #include <dali-toolkit/public-api/controls/control.h>
40 #include <dali-toolkit/public-api/controls/control-impl.h>
41 #include <dali-toolkit/public-api/controls/image-view/image-view.h>
42 #include <dali-toolkit/devel-api/accessibility-manager/accessibility-manager.h>
43 #include <dali-toolkit/devel-api/controls/control-devel.h>
44 #include <dali-toolkit/public-api/styling/style-manager.h>
45 #include <dali-toolkit/devel-api/styling/style-manager-devel.h>
46
47 namespace Dali
48 {
49
50 namespace Toolkit
51 {
52
53 namespace Internal
54 {
55
56 namespace // Unnamed namespace
57 {
58
59 #if defined(DEBUG_ENABLED)
60 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEYBOARD_FOCUS_MANAGER");
61 #endif
62
63 const char* const IS_FOCUS_GROUP_PROPERTY_NAME = "isKeyboardFocusGroup"; // This property will be replaced by a flag in Control.
64
65 const char* const FOCUS_BORDER_IMAGE_FILE_NAME = "keyboard_focus.9.png";
66
67 BaseHandle Create()
68 {
69   BaseHandle handle = KeyboardFocusManager::Get();
70
71   if ( !handle )
72   {
73     SingletonService singletonService( SingletonService::Get() );
74     if ( singletonService )
75     {
76       Toolkit::KeyboardFocusManager manager = Toolkit::KeyboardFocusManager( new Internal::KeyboardFocusManager() );
77       singletonService.Register( typeid( manager ), manager );
78       handle = manager;
79     }
80   }
81
82   return handle;
83 }
84
85 DALI_TYPE_REGISTRATION_BEGIN_CREATE( Toolkit::KeyboardFocusManager, Dali::BaseHandle, Create, true )
86
87 DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardPreFocusChange",           SIGNAL_PRE_FOCUS_CHANGE )
88 DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusChanged",             SIGNAL_FOCUS_CHANGED )
89 DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusGroupChanged",        SIGNAL_FOCUS_GROUP_CHANGED )
90 DALI_SIGNAL_REGISTRATION( Toolkit, KeyboardFocusManager, "keyboardFocusedActorEnterKey",     SIGNAL_FOCUSED_ACTOR_ENTER_KEY )
91
92 DALI_TYPE_REGISTRATION_END()
93
94 const unsigned int MAX_HISTORY_AMOUNT = 30; ///< Max length of focus history stack
95
96 } // unnamed namespace
97
98 Toolkit::KeyboardFocusManager KeyboardFocusManager::Get()
99 {
100   Toolkit::KeyboardFocusManager manager;
101
102   SingletonService singletonService( SingletonService::Get() );
103   if ( singletonService )
104   {
105     // Check whether the keyboard focus manager is already created
106     Dali::BaseHandle handle = singletonService.GetSingleton( typeid( Toolkit::KeyboardFocusManager ) );
107     if(handle)
108     {
109       // If so, downcast the handle of singleton to keyboard focus manager
110       manager = Toolkit::KeyboardFocusManager( dynamic_cast< KeyboardFocusManager* >( handle.GetObjectPtr() ) );
111     }
112   }
113
114   return manager;
115 }
116
117 KeyboardFocusManager::KeyboardFocusManager()
118 : mPreFocusChangeSignal(),
119   mFocusChangedSignal(),
120   mFocusGroupChangedSignal(),
121   mFocusedActorEnterKeySignal(),
122   mCurrentFocusActor(),
123   mFocusIndicatorActor(),
124   mFocusHistory(),
125   mSlotDelegate( this ),
126   mCustomAlgorithmInterface(NULL),
127   mCurrentFocusedWindow(),
128   mIsFocusIndicatorShown( UNKNOWN ),
129   mEnableFocusIndicator( ENABLE ),
130   mAlwaysShowIndicator( ALWAYS_SHOW ),
131   mFocusGroupLoopEnabled( false ),
132   mIsWaitingKeyboardFocusChangeCommit( false ),
133   mClearFocusOnTouch( true )
134 {
135   // TODO: Get FocusIndicatorEnable constant from stylesheet to set mIsFocusIndicatorShown.
136
137   LifecycleController::Get().InitSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnAdaptorInit );
138 }
139
140 void KeyboardFocusManager::OnAdaptorInit()
141 {
142   if( Adaptor::IsAvailable() )
143   {
144     // Retrieve all the existing scene holders
145     Dali::SceneHolderList sceneHolders = Adaptor::Get().GetSceneHolders();
146     for( auto iter = sceneHolders.begin(); iter != sceneHolders.end(); ++iter )
147     {
148       ( *iter ).KeyEventSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnKeyEvent );
149       ( *iter ).TouchSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnTouch );
150       Dali::Window window = DevelWindow::DownCast( *iter );
151       if( window )
152       {
153         window.FocusChangeSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
154       }
155     }
156
157     // Get notified when any new scene holder is created afterwards
158     Adaptor::Get().WindowCreatedSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnSceneHolderCreated );
159   }
160 }
161
162 void KeyboardFocusManager::OnSceneHolderCreated( Dali::Integration::SceneHolder& sceneHolder )
163 {
164   sceneHolder.KeyEventSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnKeyEvent );
165   sceneHolder.TouchSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnTouch );
166   Dali::Window window = DevelWindow::DownCast( sceneHolder );
167   if( window )
168   {
169     window.FocusChangeSignal().Connect( mSlotDelegate, &KeyboardFocusManager::OnWindowFocusChanged);
170   }
171 }
172
173 KeyboardFocusManager::~KeyboardFocusManager()
174 {
175 }
176
177 void KeyboardFocusManager::GetConfigurationFromStyleManger()
178 {
179     Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
180     if( styleManager )
181     {
182       Property::Map config = Toolkit::DevelStyleManager::GetConfigurations( styleManager );
183       mAlwaysShowIndicator = config["alwaysShowFocus"].Get<bool>() ? ALWAYS_SHOW : NONE;
184       mIsFocusIndicatorShown = ( mAlwaysShowIndicator == ALWAYS_SHOW )? SHOW : HIDE;
185       mClearFocusOnTouch = ( mIsFocusIndicatorShown == SHOW ) ? false : true;
186     }
187 }
188
189 bool KeyboardFocusManager::SetCurrentFocusActor( Actor actor )
190 {
191   DALI_ASSERT_DEBUG( !mIsWaitingKeyboardFocusChangeCommit && "Calling this function in the PreFocusChangeSignal callback?" );
192
193   if( mIsFocusIndicatorShown == UNKNOWN )
194   {
195     GetConfigurationFromStyleManger();
196   }
197
198   return DoSetCurrentFocusActor( actor );
199 }
200
201 bool KeyboardFocusManager::DoSetCurrentFocusActor( Actor actor )
202 {
203   bool success = false;
204   if( actor && actor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) && actor.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
205   {
206     Integration::SceneHolder currentWindow = Integration::SceneHolder::Get( actor );
207
208     if( currentWindow.GetRootLayer() != mCurrentFocusedWindow.GetHandle())
209     {
210       Layer rootLayer = currentWindow.GetRootLayer();
211       mCurrentFocusedWindow = rootLayer;
212     }
213   }
214
215   Actor currentFocusedActor = GetCurrentFocusActor();
216
217   // If developer set focus on same actor, doing nothing
218   if( actor == currentFocusedActor )
219   {
220     if( !actor )
221     {
222       return false;
223     }
224     return true;
225   }
226
227   // Check whether the actor is in the stage and is keyboard focusable.
228   if( actor && actor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) && actor.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
229   {
230     if( ( mIsFocusIndicatorShown == SHOW ) && ( mEnableFocusIndicator == ENABLE ) )
231     {
232       actor.Add( GetFocusIndicatorActor() );
233     }
234
235     // Send notification for the change of focus actor
236     if( !mFocusChangedSignal.Empty() )
237     {
238       mFocusChangedSignal.Emit(currentFocusedActor, actor);
239     }
240
241     Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast(currentFocusedActor);
242     if( currentlyFocusedControl )
243     {
244       // Do we need it to remember if it was previously DISABLED?
245       currentlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::NORMAL );
246       currentlyFocusedControl.ClearKeyInputFocus();
247     }
248
249     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] Focus Changed\n", __FUNCTION__, __LINE__);
250
251     // Save the current focused actor
252     mCurrentFocusActor = actor;
253
254     bool focusedWindowFound = false;
255     for( unsigned int i = 0; i < mCurrentFocusActors.size(); i++ )
256     {
257       if( mCurrentFocusActors[i].first == mCurrentFocusedWindow )
258       {
259         mCurrentFocusActors[i].second = actor;
260         focusedWindowFound = true;
261         break;
262       }
263     }
264     if( !focusedWindowFound)
265     {
266       // A new window gains the focus, so store the focused actor in that window.
267       mCurrentFocusActors.push_back( std::pair< WeakHandle< Layer>, WeakHandle< Actor > >( mCurrentFocusedWindow , actor ));
268     }
269
270     Toolkit::Control newlyFocusedControl = Toolkit::Control::DownCast(actor);
271     if( newlyFocusedControl )
272     {
273       newlyFocusedControl.SetProperty(DevelControl::Property::STATE, DevelControl::FOCUSED );
274       newlyFocusedControl.SetKeyInputFocus();
275     }
276
277     // Push Current Focused Actor to FocusHistory
278     mFocusHistory.push_back( actor );
279
280     // Delete first element before add new element when Stack is full.
281     if( mFocusHistory.size() > MAX_HISTORY_AMOUNT )
282     {
283        FocusStackIterator beginPos = mFocusHistory.begin();
284        mFocusHistory.erase( beginPos );
285     }
286
287     DALI_LOG_INFO( gLogFilter, Debug::General, "[%s:%d] SUCCEED\n", __FUNCTION__, __LINE__);
288     success = true;
289   }
290   else
291   {
292     DALI_LOG_WARNING("[%s:%d] FAILED\n", __FUNCTION__, __LINE__);
293   }
294
295   return success;
296 }
297
298 Actor KeyboardFocusManager::GetCurrentFocusActor()
299 {
300   Actor actor = mCurrentFocusActor.GetHandle();
301
302   if( actor && ! actor.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
303   {
304     // If the actor has been removed from the stage, then it should not be focused
305     actor.Reset();
306     mCurrentFocusActor.Reset();
307   }
308   return actor;
309 }
310
311 Actor KeyboardFocusManager::GetFocusActorFromCurrentWindow()
312 {
313   Actor actor;
314   unsigned int index;
315   for( index = 0; index < mCurrentFocusActors.size(); index++ )
316   {
317     if( mCurrentFocusActors[index].first == mCurrentFocusedWindow )
318     {
319       actor = mCurrentFocusActors[index].second.GetHandle();
320       break;
321     }
322   }
323
324   if( actor && ! actor.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
325   {
326     // If the actor has been removed from the window, then the window doesn't have any focused actor
327     actor.Reset();
328     mCurrentFocusActors.erase( mCurrentFocusActors.begin() + index );
329   }
330
331   return actor;
332 }
333
334 Actor KeyboardFocusManager::GetCurrentFocusGroup()
335 {
336   return GetFocusGroup(GetCurrentFocusActor());
337 }
338
339 void KeyboardFocusManager::MoveFocusBackward()
340 {
341   // Find Pre Focused Actor when the list size is more than 1
342   if( mFocusHistory.size() > 1 )
343   {
344     // Delete current focused actor in history
345     mFocusHistory.pop_back();
346
347     // If pre-focused actors are not on stage or deleted, remove them in stack
348     while( mFocusHistory.size() > 0 )
349     {
350       // Get pre focused actor
351       Actor target = mFocusHistory[ mFocusHistory.size() -1 ].GetHandle();
352
353       // Impl of Actor is not null
354       if( target && target.GetProperty< bool >( Actor::Property::CONNECTED_TO_SCENE ) )
355       {
356         // Delete pre focused actor in history because it will pushed again by SetCurrentFocusActor()
357         mFocusHistory.pop_back();
358         SetCurrentFocusActor( target );
359         break;
360       }
361       else
362       {
363         // Target is empty handle or off stage. Erase from queue
364         mFocusHistory.pop_back();
365       }
366     }
367
368     // if there is no actor which can get focus, then push current focus actor in stack again
369     if( mFocusHistory.size() == 0 )
370     {
371       Actor currentFocusedActor = GetCurrentFocusActor();
372       mFocusHistory.push_back( currentFocusedActor );
373     }
374   }
375 }
376
377 bool KeyboardFocusManager::IsLayoutControl(Actor actor) const
378 {
379   Toolkit::Control control = Toolkit::Control::DownCast(actor);
380   return control && GetImplementation( control ).IsKeyboardNavigationSupported();
381 }
382
383 Toolkit::Control KeyboardFocusManager::GetParentLayoutControl(Actor actor) const
384 {
385   // Get the actor's parent layout control that supports two dimensional keyboard navigation
386   Actor rootActor;
387   Actor parent;
388   if(actor)
389   {
390     Integration::SceneHolder window = Integration::SceneHolder::Get( actor );
391     if ( window )
392     {
393       rootActor = window.GetRootLayer();
394     }
395
396     parent = actor.GetParent();
397   }
398
399   while( parent && !IsLayoutControl(parent) && parent != rootActor )
400   {
401     parent = parent.GetParent();
402   }
403
404   return Toolkit::Control::DownCast(parent);
405 }
406
407 bool KeyboardFocusManager::MoveFocus(Toolkit::Control::KeyboardFocus::Direction direction)
408 {
409   Actor currentFocusActor = GetCurrentFocusActor();
410
411   bool succeed = false;
412
413   // Go through the actor's hierarchy until we find a layout control that knows how to move the focus
414   Toolkit::Control parentLayoutControl = GetParentLayoutControl( currentFocusActor );
415   while( parentLayoutControl && !succeed )
416   {
417     succeed = DoMoveFocusWithinLayoutControl( parentLayoutControl, currentFocusActor, direction );
418     parentLayoutControl = GetParentLayoutControl( parentLayoutControl );
419   }
420
421   if( !succeed )
422   {
423     Actor nextFocusableActor;
424
425     Toolkit::Control currentFocusControl = Toolkit::Control::DownCast(currentFocusActor);
426
427     // If the current focused actor is a control, then find the next focusable actor via the focusable properties.
428     if( currentFocusControl )
429     {
430       int actorId = -1;
431       Property::Index index = Property::INVALID_INDEX;
432       Property::Value value;
433
434       // Find property index based upon focus direction
435       switch ( direction )
436       {
437         case Toolkit::Control::KeyboardFocus::LEFT:
438         {
439           index = Toolkit::DevelControl::Property::LEFT_FOCUSABLE_ACTOR_ID;
440           break;
441         }
442         case Toolkit::Control::KeyboardFocus::RIGHT:
443         {
444           index = Toolkit::DevelControl::Property::RIGHT_FOCUSABLE_ACTOR_ID;
445           break;
446         }
447         case Toolkit::Control::KeyboardFocus::UP:
448         {
449           index = Toolkit::DevelControl::Property::UP_FOCUSABLE_ACTOR_ID;
450           break;
451         }
452         case Toolkit::Control::KeyboardFocus::DOWN:
453         {
454           index = Toolkit::DevelControl::Property::DOWN_FOCUSABLE_ACTOR_ID;
455           break;
456         }
457         default:
458           break;
459       }
460
461       // If the focusable property is set then determine next focusable actor
462       if( index != Property::INVALID_INDEX)
463       {
464         value = currentFocusActor.GetProperty( index );
465         actorId = value.Get<int>();
466
467         // If actor's id is valid then find actor form actor's id. The actor should be on the stage.
468         if( actorId != -1 )
469         {
470           if( currentFocusActor.GetParent() )
471           {
472             nextFocusableActor = currentFocusActor.GetParent().FindChildById( actorId );
473           }
474
475           if( !nextFocusableActor )
476           {
477             Integration::SceneHolder window = Integration::SceneHolder::Get( currentFocusActor );
478             if ( window )
479             {
480               nextFocusableActor = window.GetRootLayer().FindChildById( actorId );
481             }
482           }
483         }
484       }
485     }
486
487     if( !nextFocusableActor )
488     {
489       // If the implementation of CustomAlgorithmInterface is provided then the PreFocusChangeSignal is no longer emitted.
490       if( mCustomAlgorithmInterface )
491       {
492         mIsWaitingKeyboardFocusChangeCommit = true;
493         nextFocusableActor = mCustomAlgorithmInterface->GetNextFocusableActor( currentFocusActor, Actor(), direction );
494         mIsWaitingKeyboardFocusChangeCommit = false;
495       }
496       else if( !mPreFocusChangeSignal.Empty() )
497       {
498         // Don't know how to move the focus further. The application needs to tell us which actor to move the focus to
499         mIsWaitingKeyboardFocusChangeCommit = true;
500         nextFocusableActor = mPreFocusChangeSignal.Emit( currentFocusActor, Actor(), direction );
501         mIsWaitingKeyboardFocusChangeCommit = false;
502       }
503     }
504
505     if( nextFocusableActor && nextFocusableActor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ) )
506     {
507       // Whether the next focusable actor is a layout control
508       if( IsLayoutControl( nextFocusableActor ) )
509       {
510         // If so, move the focus inside it.
511         Toolkit::Control layoutControl = Toolkit::Control::DownCast( nextFocusableActor) ;
512         succeed = DoMoveFocusWithinLayoutControl( layoutControl, currentFocusActor, direction );
513       }
514       else
515       {
516         // Otherwise, just set focus to the next focusable actor
517         succeed = SetCurrentFocusActor( nextFocusableActor );
518       }
519     }
520   }
521
522   return succeed;
523 }
524
525 bool KeyboardFocusManager::DoMoveFocusWithinLayoutControl(Toolkit::Control control, Actor actor, Toolkit::Control::KeyboardFocus::Direction direction)
526 {
527   // Ask the control for the next actor to focus
528   Actor nextFocusableActor = GetImplementation( control ).GetNextKeyboardFocusableActor(actor, direction, mFocusGroupLoopEnabled);
529   if(nextFocusableActor)
530   {
531     if(!nextFocusableActor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ))
532     {
533       // If the actor is not focusable, ask the same layout control for the next actor to focus
534       return DoMoveFocusWithinLayoutControl(control, nextFocusableActor, direction);
535     }
536     else
537     {
538       Actor currentFocusActor = GetCurrentFocusActor();
539       Actor committedFocusActor = nextFocusableActor;
540
541       // We will try to move the focus to the actor. Emit a signal to notify the proposed actor to focus
542       // Signal handler can check the proposed actor and return a different actor if it wishes.
543       if( !mPreFocusChangeSignal.Empty() )
544       {
545         mIsWaitingKeyboardFocusChangeCommit = true;
546         committedFocusActor = mPreFocusChangeSignal.Emit(currentFocusActor, nextFocusableActor, direction);
547         mIsWaitingKeyboardFocusChangeCommit = false;
548       }
549
550       if (committedFocusActor && committedFocusActor.GetProperty< bool >( Actor::Property::KEYBOARD_FOCUSABLE ))
551       {
552         // Whether the commited focusable actor is a layout control
553         if(IsLayoutControl(committedFocusActor))
554         {
555           // If so, move the focus inside it.
556           Toolkit::Control layoutControl = Toolkit::Control::DownCast(committedFocusActor);
557           return DoMoveFocusWithinLayoutControl(layoutControl, currentFocusActor, direction);
558         }
559         else
560         {
561           // Otherwise, just set focus to the next focusable actor
562           if(committedFocusActor == nextFocusableActor)
563           {
564             // If the application hasn't changed our proposed actor, we informs the layout control we will
565             // move the focus to what the control returns. The control might wish to perform some actions
566             // before the focus is actually moved.
567             GetImplementation( control ).OnKeyboardFocusChangeCommitted( committedFocusActor );
568           }
569
570           return SetCurrentFocusActor(committedFocusActor);
571         }
572       }
573       else
574       {
575         return false;
576       }
577     }
578   }
579   else
580   {
581     // No more actor can be focused in the given direction within the same layout control.
582     return false;
583   }
584 }
585
586 bool KeyboardFocusManager::DoMoveFocusToNextFocusGroup(bool forward)
587 {
588   bool succeed = false;
589
590   // Get the parent layout control of the current focus group
591   Toolkit::Control parentLayoutControl = GetParentLayoutControl(GetCurrentFocusGroup());
592
593   while(parentLayoutControl && !succeed)
594   {
595     // If the current focus group has a parent layout control, we can probably automatically
596     // move the focus to the next focus group in the forward or backward direction.
597     Toolkit::Control::KeyboardFocus::Direction direction = forward ? Toolkit::Control::KeyboardFocus::RIGHT : Toolkit::Control::KeyboardFocus::LEFT;
598     succeed = DoMoveFocusWithinLayoutControl(parentLayoutControl, GetCurrentFocusActor(), direction);
599     parentLayoutControl = GetParentLayoutControl(parentLayoutControl);
600   }
601
602   if(!mFocusGroupChangedSignal.Empty())
603   {
604     // Emit a focus group changed signal. The applicaton can move the focus to a new focus group
605     mFocusGroupChangedSignal.Emit(GetCurrentFocusActor(), forward);
606   }
607
608   return succeed;
609 }
610
611 void KeyboardFocusManager::DoKeyboardEnter(Actor actor)
612 {
613   if( actor )
614   {
615     Toolkit::Control control = Toolkit::Control::DownCast( actor );
616     if( control )
617     {
618       // Notify the control that enter has been pressed on it.
619       GetImplementation( control ).KeyboardEnter();
620     }
621
622     // Send a notification for the actor.
623     if( !mFocusedActorEnterKeySignal.Empty() )
624     {
625       mFocusedActorEnterKeySignal.Emit( actor );
626     }
627   }
628 }
629
630 void KeyboardFocusManager::ClearFocus()
631 {
632   Actor actor = GetCurrentFocusActor();
633   if( actor )
634   {
635     if( mFocusIndicatorActor )
636     {
637       actor.Remove( mFocusIndicatorActor );
638     }
639
640     // Send notification for the change of focus actor
641     if( !mFocusChangedSignal.Empty() )
642     {
643       mFocusChangedSignal.Emit( actor, Actor() );
644     }
645
646     Toolkit::Control currentlyFocusedControl = Toolkit::Control::DownCast( actor );
647     if( currentlyFocusedControl )
648     {
649       currentlyFocusedControl.SetProperty( DevelControl::Property::STATE, DevelControl::NORMAL );
650       currentlyFocusedControl.ClearKeyInputFocus();
651     }
652   }
653
654   mCurrentFocusActor.Reset();
655   mIsFocusIndicatorShown = ( mAlwaysShowIndicator == ALWAYS_SHOW ) ? SHOW : HIDE;
656 }
657
658 void KeyboardFocusManager::SetFocusGroupLoop(bool enabled)
659 {
660   mFocusGroupLoopEnabled = enabled;
661 }
662
663 bool KeyboardFocusManager::GetFocusGroupLoop() const
664 {
665   return mFocusGroupLoopEnabled;
666 }
667
668 void KeyboardFocusManager::SetAsFocusGroup(Actor actor, bool isFocusGroup)
669 {
670   if(actor)
671   {
672     // Create/Set focus group property.
673     actor.RegisterProperty( IS_FOCUS_GROUP_PROPERTY_NAME, isFocusGroup, Property::READ_WRITE );
674   }
675 }
676
677 bool KeyboardFocusManager::IsFocusGroup(Actor actor) const
678 {
679   // Check whether the actor is a focus group
680   bool isFocusGroup = false;
681
682   if(actor)
683   {
684     Property::Index propertyIsFocusGroup = actor.GetPropertyIndex(IS_FOCUS_GROUP_PROPERTY_NAME);
685     if(propertyIsFocusGroup != Property::INVALID_INDEX)
686     {
687       isFocusGroup = actor.GetProperty<bool>(propertyIsFocusGroup);
688     }
689   }
690
691   return isFocusGroup;
692 }
693
694 Actor KeyboardFocusManager::GetFocusGroup(Actor actor)
695 {
696   // Go through the actor's hierarchy to check which focus group the actor belongs to
697   while (actor && !IsFocusGroup(actor))
698   {
699     actor = actor.GetParent();
700   }
701
702   return actor;
703 }
704
705 void KeyboardFocusManager::SetFocusIndicatorActor(Actor indicator)
706 {
707   if(mFocusIndicatorActor != indicator)
708   {
709     Actor currentFocusActor = GetCurrentFocusActor();
710     if(currentFocusActor)
711     {
712       // The new focus indicator should be added to the current focused actor immediately
713       if(mFocusIndicatorActor)
714       {
715         currentFocusActor.Remove(mFocusIndicatorActor);
716       }
717
718       if(indicator)
719       {
720         currentFocusActor.Add(indicator);
721       }
722     }
723
724     mFocusIndicatorActor = indicator;
725   }
726 }
727
728 Actor KeyboardFocusManager::GetFocusIndicatorActor()
729 {
730   if( ! mFocusIndicatorActor )
731   {
732     // Create the default if it hasn't been set and one that's shared by all the keyboard focusable actors
733     const std::string imageDirPath = AssetManager::GetDaliImagePath();
734     mFocusIndicatorActor = Toolkit::ImageView::New( imageDirPath + FOCUS_BORDER_IMAGE_FILE_NAME );
735
736     // Apply size constraint to the focus indicator
737     mFocusIndicatorActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
738   }
739
740   mFocusIndicatorActor.SetProperty( Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER );
741   mFocusIndicatorActor.SetProperty( Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER );
742   mFocusIndicatorActor.SetProperty( Actor::Property::POSITION, Vector2(0.0f, 0.0f));
743
744   return mFocusIndicatorActor;
745 }
746
747 void KeyboardFocusManager::OnKeyEvent(const KeyEvent& event)
748 {
749   AccessibilityAdaptor accessibilityAdaptor = AccessibilityAdaptor::Get();
750   bool isAccessibilityEnabled = accessibilityAdaptor.IsEnabled();
751
752   Toolkit::AccessibilityManager accessibilityManager = Toolkit::AccessibilityManager::Get();
753
754   std::string keyName = event.keyPressedName;
755
756   if( mIsFocusIndicatorShown == UNKNOWN )
757   {
758     GetConfigurationFromStyleManger();
759   }
760
761   bool isFocusStartableKey = false;
762
763   if(event.state == KeyEvent::Down)
764   {
765     if (keyName == "Left")
766     {
767       if(!isAccessibilityEnabled)
768       {
769         if(mIsFocusIndicatorShown == HIDE)
770         {
771           // Show focus indicator
772           mIsFocusIndicatorShown = SHOW;
773         }
774         else
775         {
776           // Move the focus towards left
777           MoveFocus(Toolkit::Control::KeyboardFocus::LEFT);
778         }
779
780         isFocusStartableKey = true;
781       }
782       else
783       {
784         // Move the accessibility focus backward
785         accessibilityManager.MoveFocusBackward();
786       }
787     }
788     else if (keyName == "Right")
789     {
790       if(!isAccessibilityEnabled)
791       {
792         if( mIsFocusIndicatorShown == HIDE )
793         {
794           // Show focus indicator
795           mIsFocusIndicatorShown = SHOW;
796         }
797         else
798         {
799           // Move the focus towards right
800           MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
801         }
802       }
803       else
804       {
805         // Move the accessibility focus forward
806         accessibilityManager.MoveFocusForward();
807       }
808
809       isFocusStartableKey = true;
810     }
811     else if (keyName == "Up" && !isAccessibilityEnabled)
812     {
813       if( mIsFocusIndicatorShown == HIDE )
814       {
815         // Show focus indicator
816         mIsFocusIndicatorShown = SHOW;
817       }
818       else
819       {
820         // Move the focus towards up
821         MoveFocus(Toolkit::Control::KeyboardFocus::UP);
822       }
823
824       isFocusStartableKey = true;
825     }
826     else if (keyName == "Down" && !isAccessibilityEnabled)
827     {
828       if( mIsFocusIndicatorShown == HIDE )
829       {
830         // Show focus indicator
831         mIsFocusIndicatorShown = SHOW;
832       }
833       else
834       {
835         // Move the focus towards down
836         MoveFocus(Toolkit::Control::KeyboardFocus::DOWN);
837       }
838
839       isFocusStartableKey = true;
840     }
841     else if (keyName == "Prior" && !isAccessibilityEnabled)
842     {
843       if( mIsFocusIndicatorShown == HIDE )
844       {
845         // Show focus indicator
846         mIsFocusIndicatorShown = SHOW;
847       }
848       else
849       {
850         // Move the focus towards the previous page
851         MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_UP);
852       }
853
854       isFocusStartableKey = true;
855     }
856     else if (keyName == "Next" && !isAccessibilityEnabled)
857     {
858       if( mIsFocusIndicatorShown == HIDE )
859       {
860         // Show focus indicator
861         mIsFocusIndicatorShown = SHOW;
862       }
863       else
864       {
865         // Move the focus towards the next page
866         MoveFocus(Toolkit::Control::KeyboardFocus::PAGE_DOWN);
867       }
868
869       isFocusStartableKey = true;
870     }
871     else if (keyName == "Tab" && !isAccessibilityEnabled)
872     {
873       if( mIsFocusIndicatorShown == HIDE )
874       {
875         // Show focus indicator
876         mIsFocusIndicatorShown = SHOW;
877       }
878       else
879       {
880         // "Tab" key changes the focus group in the forward direction and
881         // "Shift-Tab" key changes it in the backward direction.
882         DoMoveFocusToNextFocusGroup(!event.IsShiftModifier());
883       }
884
885       isFocusStartableKey = true;
886     }
887     else if (keyName == "space" && !isAccessibilityEnabled)
888     {
889       if( mIsFocusIndicatorShown == HIDE )
890       {
891         // Show focus indicator
892         mIsFocusIndicatorShown = SHOW;
893       }
894
895       isFocusStartableKey = true;
896     }
897     else if (keyName == "" && !isAccessibilityEnabled)
898     {
899       // Check the fake key event for evas-plugin case
900       if( mIsFocusIndicatorShown == HIDE )
901       {
902         // Show focus indicator
903         mIsFocusIndicatorShown = SHOW;
904       }
905
906       isFocusStartableKey = true;
907     }
908     else if (keyName == "Backspace" && !isAccessibilityEnabled)
909     {
910       // Emit signal to go back to the previous view???
911     }
912     else if (keyName == "Escape" && !isAccessibilityEnabled)
913     {
914     }
915   }
916   else if(event.state == KeyEvent::Up)
917   {
918     if (keyName == "Return")
919     {
920       if((mIsFocusIndicatorShown == HIDE) && !isAccessibilityEnabled)
921       {
922         // Show focus indicator
923         mIsFocusIndicatorShown = SHOW;
924       }
925       else
926       {
927         // The focused actor has enter pressed on it
928         Actor actor;
929         if( !isAccessibilityEnabled )
930         {
931           actor = GetCurrentFocusActor();
932         }
933         else
934         {
935           actor = accessibilityManager.GetCurrentFocusActor();
936         }
937
938         if( actor )
939         {
940           DoKeyboardEnter( actor );
941         }
942       }
943
944       isFocusStartableKey = true;
945     }
946   }
947
948   if(isFocusStartableKey && ( mIsFocusIndicatorShown == SHOW ) && !isAccessibilityEnabled)
949   {
950     Actor actor = GetCurrentFocusActor();
951     if( actor )
952     {
953       if( mEnableFocusIndicator == ENABLE )
954       {
955         // Make sure the focused actor is highlighted
956         actor.Add( GetFocusIndicatorActor() );
957       }
958     }
959     else
960     {
961       // No actor is focused but keyboard focus is activated by the key press
962       // Let's try to move the initial focus
963       MoveFocus(Toolkit::Control::KeyboardFocus::RIGHT);
964     }
965   }
966 }
967
968 void KeyboardFocusManager::OnTouch(const TouchData& touch)
969 {
970   // if mIsFocusIndicatorShown is UNKNOWN, it means Configuration is not loaded.
971   // Try to load configuration.
972   if( mIsFocusIndicatorShown == UNKNOWN )
973   {
974     GetConfigurationFromStyleManger();
975   }
976
977   // Clear the focus when user touch the screen.
978   // We only do this on a Down event, otherwise the clear action may override a manually focused actor.
979   // If mClearFocusOnTouch is false, do not clear the focus even if user touch the screen.
980   if( (( touch.GetPointCount() < 1 ) || ( touch.GetState( 0 ) == PointState::DOWN )) && mClearFocusOnTouch )
981   {
982     ClearFocus();
983   }
984 }
985
986 void KeyboardFocusManager::OnWindowFocusChanged(Window window, bool focusIn )
987 {
988   if( focusIn && mCurrentFocusedWindow.GetHandle() != window.GetRootLayer() )
989   {
990     // Change Current Focused Window
991     Layer rootLayer = window.GetRootLayer();
992     mCurrentFocusedWindow = rootLayer;
993
994     // Get Current Focused Actor from window
995     Actor currentFocusedActor = GetFocusActorFromCurrentWindow();
996     SetCurrentFocusActor( currentFocusedActor );
997
998     if( currentFocusedActor && ( mEnableFocusIndicator == ENABLE ) )
999     {
1000       // Make sure the focused actor is highlighted
1001       currentFocusedActor.Add( GetFocusIndicatorActor() );
1002       mIsFocusIndicatorShown = SHOW;
1003     }
1004   }
1005 }
1006
1007 Toolkit::KeyboardFocusManager::PreFocusChangeSignalType& KeyboardFocusManager::PreFocusChangeSignal()
1008 {
1009   return mPreFocusChangeSignal;
1010 }
1011
1012 Toolkit::KeyboardFocusManager::FocusChangedSignalType& KeyboardFocusManager::FocusChangedSignal()
1013 {
1014   return mFocusChangedSignal;
1015 }
1016
1017 Toolkit::KeyboardFocusManager::FocusGroupChangedSignalType& KeyboardFocusManager::FocusGroupChangedSignal()
1018 {
1019   return mFocusGroupChangedSignal;
1020 }
1021
1022 Toolkit::KeyboardFocusManager::FocusedActorEnterKeySignalType& KeyboardFocusManager::FocusedActorEnterKeySignal()
1023 {
1024   return mFocusedActorEnterKeySignal;
1025 }
1026
1027 bool KeyboardFocusManager::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
1028 {
1029   Dali::BaseHandle handle( object );
1030
1031   bool connected( true );
1032   KeyboardFocusManager* manager = static_cast< KeyboardFocusManager* >( object ); // TypeRegistry guarantees that this is the correct type.
1033
1034   if( 0 == strcmp( signalName.c_str(), SIGNAL_PRE_FOCUS_CHANGE ) )
1035   {
1036     manager->PreFocusChangeSignal().Connect( tracker, functor );
1037   }
1038   else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_CHANGED ) )
1039   {
1040     manager->FocusChangedSignal().Connect( tracker, functor );
1041   }
1042   else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUS_GROUP_CHANGED ) )
1043   {
1044     manager->FocusGroupChangedSignal().Connect( tracker, functor );
1045   }
1046   else if( 0 == strcmp( signalName.c_str(), SIGNAL_FOCUSED_ACTOR_ENTER_KEY ) )
1047   {
1048     manager->FocusedActorEnterKeySignal().Connect( tracker, functor );
1049   }
1050   else
1051   {
1052     // signalName does not match any signal
1053     connected = false;
1054   }
1055
1056   return connected;
1057 }
1058
1059 void KeyboardFocusManager::SetCustomAlgorithm(CustomAlgorithmInterface& interface)
1060 {
1061   mCustomAlgorithmInterface = &interface;
1062 }
1063
1064 void KeyboardFocusManager::EnableFocusIndicator(bool enable)
1065 {
1066   if( !enable && mFocusIndicatorActor )
1067   {
1068     mFocusIndicatorActor.Unparent();
1069   }
1070
1071   mEnableFocusIndicator = enable? ENABLE : DISABLE;
1072
1073 }
1074
1075 bool KeyboardFocusManager::IsFocusIndicatorEnabled() const
1076 {
1077   return ( mEnableFocusIndicator == ENABLE );
1078 }
1079
1080 } // namespace Internal
1081
1082 } // namespace Toolkit
1083
1084 } // namespace Dali