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