[AT-SPI] do not keep window in ApplicationAccessible
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
1 /*
2  * Copyright (c) 2021 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
20 // EXTERNAL INCLUDES
21 #include <dali/devel-api/common/stage.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/actors/layer.h>
24 #include <iostream>
25 #include <unordered_map>
26
27 // INTERNAL INCLUDES
28 #include <dali/devel-api/adaptor-framework/environment-variable.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
31 #include <dali/internal/accessibility/bridge/bridge-action.h>
32 #include <dali/internal/accessibility/bridge/bridge-collection.h>
33 #include <dali/internal/accessibility/bridge/bridge-component.h>
34 #include <dali/internal/accessibility/bridge/bridge-editable-text.h>
35 #include <dali/internal/accessibility/bridge/bridge-hypertext.h>
36 #include <dali/internal/accessibility/bridge/bridge-hyperlink.h>
37 #include <dali/internal/accessibility/bridge/bridge-object.h>
38 #include <dali/internal/accessibility/bridge/bridge-selection.h>
39 #include <dali/internal/accessibility/bridge/bridge-socket.h>
40 #include <dali/internal/accessibility/bridge/bridge-text.h>
41 #include <dali/internal/accessibility/bridge/bridge-value.h>
42 #include <dali/internal/accessibility/bridge/bridge-application.h>
43 #include <dali/internal/accessibility/bridge/dummy-atspi.h>
44 #include <dali/internal/adaptor/common/adaptor-impl.h>
45 #include <dali/internal/system/common/environment-variables.h>
46
47 using namespace Dali::Accessibility;
48
49 namespace // unnamed namespace
50 {
51
52 const int RETRY_INTERVAL = 1000;
53
54 } // unnamed namespace
55
56 /**
57  * @brief The BridgeImpl class is to implement some Bridge functions.
58  */
59 class BridgeImpl : public virtual BridgeBase,
60                    public BridgeAccessible,
61                    public BridgeObject,
62                    public BridgeComponent,
63                    public BridgeCollection,
64                    public BridgeAction,
65                    public BridgeValue,
66                    public BridgeText,
67                    public BridgeEditableText,
68                    public BridgeSelection,
69                    public BridgeApplication,
70                    public BridgeHypertext,
71                    public BridgeHyperlink,
72                    public BridgeSocket
73 {
74   DBus::DBusClient                                              mAccessibilityStatusClient;
75   DBus::DBusClient                                              mRegistryClient;
76   DBus::DBusClient                                              mDirectReadingClient;
77   bool                                                          mIsScreenReaderEnabled = false;
78   bool                                                          mIsEnabled             = false;
79   bool                                                          mIsShown               = false;
80   std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks;
81   Dali::Actor                                                   mHighlightedActor;
82   std::function<void(Dali::Actor)>                              mHighlightClearAction;
83   Dali::CallbackBase*                                           mIdleCallback          = NULL;
84   Dali::Timer                                                   mInitializeTimer;
85   Dali::Timer                                                   mReadIsEnabledTimer;
86   Dali::Timer                                                   mReadScreenReaderEnabledTimer;
87   Dali::Timer                                                   mForceUpTimer;
88
89 public:
90   BridgeImpl()
91   {
92   }
93
94   /**
95    * @copydoc Dali::Accessibility::Bridge::Emit()
96    */
97   Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
98   {
99     if(!IsUp())
100     {
101       return Consumed::NO;
102     }
103
104     unsigned int keyType = 0;
105
106     switch(type)
107     {
108       case KeyEventType::KEY_PRESSED:
109       {
110         keyType = 0;
111         break;
112       }
113       case KeyEventType::KEY_RELEASED:
114       {
115         keyType = 1;
116         break;
117       }
118       default:
119       {
120         return Consumed::NO;
121       }
122     }
123
124     auto methodObject = mRegistryClient.method<bool(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>)>("NotifyListenersSync");
125     auto result       = methodObject.call(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>{keyType, 0, static_cast<int32_t>(keyCode), 0, static_cast<int32_t>(timeStamp), keyName, isText ? 1 : 0});
126     if(!result)
127     {
128       LOG() << result.getError().message;
129       return Consumed::NO;
130     }
131     return std::get<0>(result) ? Consumed::YES : Consumed::NO;
132   }
133
134   /**
135    * @copydoc Dali::Accessibility::Bridge::Pause()
136    */
137   void Pause() override
138   {
139     if(!IsUp())
140     {
141       return;
142     }
143
144     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
145       if(!msg)
146       {
147         LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
148       }
149     },
150                                                                                         true);
151   }
152
153   /**
154    * @copydoc Dali::Accessibility::Bridge::Resume()
155    */
156   void Resume() override
157   {
158     if(!IsUp())
159     {
160       return;
161     }
162
163     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
164       if(!msg)
165       {
166         LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
167       }
168     },
169                                                                                         false);
170   }
171
172   /**
173    * @copydoc Dali::Accessibility::Bridge::StopReading()
174    */
175   void StopReading(bool alsoNonDiscardable) override
176   {
177     if(!IsUp())
178     {
179       return;
180     }
181
182     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
183       if(!msg)
184       {
185         LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
186       }
187     },
188                                                                                         alsoNonDiscardable);
189   }
190
191   /**
192    * @copydoc Dali::Accessibility::Bridge::Say()
193    */
194   void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
195   {
196     if(!IsUp())
197     {
198       return;
199     }
200
201     mDirectReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
202       if(!msg)
203       {
204         LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
205       }
206       else if(callback)
207       {
208         mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
209       }
210     },
211                                                                                                                            text,
212                                                                                                                            discardable);
213   }
214
215   /**
216    * @copydoc Dali::Accessibility::Bridge::ForceDown()
217    */
218   void ForceDown() override
219   {
220     if(mData)
221     {
222       if(mData->mCurrentlyHighlightedActor && mData->mHighlightActor)
223       {
224         mData->mCurrentlyHighlightedActor.Remove(mData->mHighlightActor);
225       }
226       mData->mCurrentlyHighlightedActor = {};
227       mData->mHighlightActor            = {};
228
229       mDisabledSignal.Emit();
230     }
231     mHighlightedActor     = {};
232     mHighlightClearAction = {};
233     BridgeAccessible::ForceDown();
234     mRegistryClient       = {};
235     mDirectReadingClient  = {};
236     mDirectReadingCallbacks.clear();
237     mApplication.mChildren.clear();
238     ClearTimer();
239   }
240
241   void ClearTimer()
242   {
243     if(mInitializeTimer)
244     {
245       mInitializeTimer.Stop();
246       mInitializeTimer.Reset();
247     }
248
249     if(mReadIsEnabledTimer)
250     {
251       mReadIsEnabledTimer.Stop();
252       mReadIsEnabledTimer.Reset();
253     }
254
255     if(mReadScreenReaderEnabledTimer)
256     {
257       mReadScreenReaderEnabledTimer.Stop();
258       mReadScreenReaderEnabledTimer.Reset();
259     }
260
261     if(mForceUpTimer)
262     {
263       mForceUpTimer.Stop();
264       mForceUpTimer.Reset();
265     }
266   }
267
268   /**
269    * @copydoc Dali::Accessibility::Bridge::Terminate()
270    */
271   void Terminate() override
272   {
273     if(mData)
274     {
275       mData->mCurrentlyHighlightedActor = {};
276       mData->mHighlightActor            = {};
277     }
278     ForceDown();
279     if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
280     {
281       Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
282     }
283     mAccessibilityStatusClient        = {};
284     mDbusServer                       = {};
285     mConnectionPtr                    = {};
286   }
287
288   bool ForceUpTimerCallback()
289   {
290     if(ForceUp() != ForceUpResult::FAILED)
291     {
292       return false;
293     }
294     return true;
295   }
296
297   /**
298    * @copydoc Dali::Accessibility::Bridge::ForceUp()
299    */
300   ForceUpResult ForceUp() override
301   {
302     auto forceUpResult = BridgeAccessible::ForceUp();
303     if(forceUpResult == ForceUpResult::ALREADY_UP)
304     {
305       return forceUpResult;
306     }
307     else if(forceUpResult == ForceUpResult::FAILED)
308     {
309       if(!mForceUpTimer)
310       {
311         mForceUpTimer = Dali::Timer::New(RETRY_INTERVAL);
312         mForceUpTimer.TickSignal().Connect(this, &BridgeImpl::ForceUpTimerCallback);
313         mForceUpTimer.Start();
314       }
315       return forceUpResult;
316     }
317
318     BridgeObject::RegisterInterfaces();
319     BridgeAccessible::RegisterInterfaces();
320     BridgeComponent::RegisterInterfaces();
321     BridgeCollection::RegisterInterfaces();
322     BridgeAction::RegisterInterfaces();
323     BridgeValue::RegisterInterfaces();
324     BridgeText::RegisterInterfaces();
325     BridgeEditableText::RegisterInterfaces();
326     BridgeSelection::RegisterInterfaces();
327     BridgeApplication::RegisterInterfaces();
328     BridgeHypertext::RegisterInterfaces();
329     BridgeHyperlink::RegisterInterfaces();
330     BridgeSocket::RegisterInterfaces();
331
332     RegisterOnBridge(&mApplication);
333
334     mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
335     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
336
337     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
338       auto it = mDirectReadingCallbacks.find(id);
339       if(it != mDirectReadingCallbacks.end())
340       {
341         it->second(readingState);
342         if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
343         {
344           mDirectReadingCallbacks.erase(it);
345         }
346       }
347     });
348
349     auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
350     Address root{"", "root"};
351     auto    res = proxy.method<Address(Address)>("Embed").call(root);
352     if(!res)
353     {
354       LOG() << "Call to Embed failed: " << res.getError().message;
355     }
356     assert(res);
357
358     mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
359
360     mEnabledSignal.Emit();
361
362     return ForceUpResult::JUST_STARTED;
363   }
364
365   /**
366    * @brief Sends a signal to dbus that the window is shown.
367    *
368    * @param[in] window The window to be shown
369    * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
370    */
371   void EmitShown(Dali::Window window)
372   {
373     auto windowAccessible = mApplication.GetWindowAccessible(window);
374     if(windowAccessible)
375     {
376       windowAccessible->EmitShowing(true);
377     }
378   }
379
380   /**
381    * @brief Sends a signal to dbus that the window is hidden.
382    *
383    * @param[in] window The window to be hidden
384    * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
385    */
386   void EmitHidden(Dali::Window window)
387   {
388     auto windowAccessible = mApplication.GetWindowAccessible(window);
389     if(windowAccessible)
390     {
391       windowAccessible->EmitShowing(false);
392     }
393   }
394
395   /**
396    * @brief Sends a signal to dbus that the window is activated.
397    *
398    * @param[in] window The window to be activated
399    * @see BridgeObject::Emit()
400    */
401   void EmitActivate(Dali::Window window)
402   {
403     auto windowAccessible = mApplication.GetWindowAccessible(window);
404     if(windowAccessible)
405     {
406       windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
407     }
408   }
409
410   /**
411    * @brief Sends a signal to dbus that the window is deactivated.
412    *
413    * @param[in] window The window to be deactivated
414    * @see BridgeObject::Emit()
415    */
416   void EmitDeactivate(Dali::Window window)
417   {
418     auto windowAccessible = mApplication.GetWindowAccessible(window);
419     if(windowAccessible)
420     {
421       windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
422     }
423   }
424
425   /**
426    * @copydoc Dali::Accessibility::Bridge::WindowShown()
427    */
428   void WindowShown(Dali::Window window) override
429   {
430     if(!mIsShown && IsUp())
431     {
432       EmitShown(window);
433     }
434     mIsShown = true;
435   }
436
437   /**
438    * @copydoc Dali::Accessibility::Bridge::WindowHidden()
439    */
440   void WindowHidden(Dali::Window window) override
441   {
442     if(mIsShown && IsUp())
443     {
444       EmitHidden(window);
445     }
446     mIsShown = false;
447   }
448
449   /**
450    * @copydoc Dali::Accessibility::Bridge::WindowFocused()
451    */
452   void WindowFocused(Dali::Window window) override
453   {
454     if(mIsShown && IsUp())
455     {
456       EmitActivate(window);
457     }
458   }
459
460   /**
461    * @copydoc Dali::Accessibility::Bridge::WindowUnfocused()
462    */
463   void WindowUnfocused(Dali::Window window) override
464   {
465     if(mIsShown && IsUp())
466     {
467       EmitDeactivate(window);
468     }
469   }
470
471   /**
472    * @copydoc Dali::Accessibility::Bridge::SuppressScreenReader()
473    */
474   void SuppressScreenReader(bool suppress) override
475   {
476     if(mIsScreenReaderSuppressed == suppress)
477     {
478       return;
479     }
480     mIsScreenReaderSuppressed = suppress;
481     ReadScreenReaderEnabledProperty();
482   }
483
484   void SwitchBridge()
485   {
486     if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
487     {
488       ForceUp();
489     }
490     else
491     {
492       ForceDown();
493     }
494   }
495
496   bool ReadIsEnabledTimerCallback()
497   {
498     ReadIsEnabledProperty();
499     return false;
500   }
501
502   void ReadIsEnabledProperty()
503   {
504     mAccessibilityStatusClient.property<bool>("IsEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
505       if(!msg)
506       {
507         DALI_LOG_ERROR("Get IsEnabled property error: %s\n", msg.getError().message.c_str());
508         if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
509         {
510           if(!mReadIsEnabledTimer)
511           {
512             mReadIsEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
513             mReadIsEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadIsEnabledTimerCallback);
514           }
515           mReadIsEnabledTimer.Start();
516         }
517         return;
518       }
519
520       if(mReadIsEnabledTimer)
521       {
522         mReadIsEnabledTimer.Stop();
523         mReadIsEnabledTimer.Reset();
524       }
525
526       mIsEnabled = std::get<0>(msg);
527       SwitchBridge();
528     });
529   }
530
531   void ListenIsEnabledProperty()
532   {
533     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
534       mIsEnabled = res;
535       SwitchBridge();
536     });
537   }
538
539   bool ReadScreenReaderEnabledTimerCallback()
540   {
541     ReadScreenReaderEnabledProperty();
542     return false;
543   }
544
545   void ReadScreenReaderEnabledProperty()
546   {
547     // can be true because of SuppressScreenReader before init
548     if (!mAccessibilityStatusClient)
549     {
550       return;
551     }
552
553     mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
554       if(!msg)
555       {
556         DALI_LOG_ERROR("Get ScreenReaderEnabled property error: %s\n", msg.getError().message.c_str());
557         if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
558         {
559           if(!mReadScreenReaderEnabledTimer)
560           {
561             mReadScreenReaderEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
562             mReadScreenReaderEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadScreenReaderEnabledTimerCallback);
563           }
564           mReadScreenReaderEnabledTimer.Start();
565         }
566         return;
567       }
568
569       if(mReadScreenReaderEnabledTimer)
570       {
571         mReadScreenReaderEnabledTimer.Stop();
572         mReadScreenReaderEnabledTimer.Reset();
573       }
574
575       mIsScreenReaderEnabled = std::get<0>(msg);
576       SwitchBridge();
577     });
578   }
579
580   void EmitScreenReaderEnabledSignal()
581   {
582     if (mIsScreenReaderEnabled)
583     {
584       mScreenReaderEnabledSignal.Emit();
585     }
586     else
587     {
588       mScreenReaderDisabledSignal.Emit();
589     }
590   }
591
592   void ListenScreenReaderEnabledProperty()
593   {
594     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
595       mIsScreenReaderEnabled = res;
596       EmitScreenReaderEnabledSignal();
597       SwitchBridge();
598     });
599   }
600
601   void ReadAndListenProperties()
602   {
603     ReadIsEnabledProperty();
604     ListenIsEnabledProperty();
605
606     ReadScreenReaderEnabledProperty();
607     ListenScreenReaderEnabledProperty();
608   }
609
610   bool InitializeAccessibilityStatusClient()
611   {
612     mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
613
614     if (!mAccessibilityStatusClient)
615     {
616       DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
617       return false;
618     }
619
620     return true;
621   }
622
623   bool InitializeTimerCallback()
624   {
625     if ( InitializeAccessibilityStatusClient() )
626     {
627       ReadAndListenProperties();
628       return false;
629     }
630     return true;
631   }
632
633   bool OnIdleSignal()
634   {
635     if ( InitializeAccessibilityStatusClient() )
636     {
637       ReadAndListenProperties();
638       mIdleCallback = NULL;
639       return false;
640     }
641
642     if(!mInitializeTimer)
643     {
644       mInitializeTimer = Dali::Timer::New(RETRY_INTERVAL);
645       mInitializeTimer.TickSignal().Connect(this, &BridgeImpl::InitializeTimerCallback);
646     }
647     mInitializeTimer.Start();
648
649     mIdleCallback = NULL;
650     return false;
651   }
652
653   /**
654    * @copydoc Dali::Accessibility::Bridge::Initialize()
655    */
656   void Initialize() override
657   {
658     if ( InitializeAccessibilityStatusClient() )
659     {
660       ReadAndListenProperties();
661       return;
662     }
663
664     // Initialize failed. Try it again on Idle
665     if( Dali::Adaptor::IsAvailable() )
666     {
667       Dali::Adaptor& adaptor = Dali::Adaptor::Get();
668       if( NULL == mIdleCallback )
669       {
670         mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
671         adaptor.AddIdle( mIdleCallback, true );
672       }
673     }
674   }
675
676   /**
677    * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
678    */
679   bool GetScreenReaderEnabled() override
680   {
681     return mIsScreenReaderEnabled;
682   }
683
684   /**
685    * @copydoc Dali::Accessibility::Bridge::IsEnabled()
686    */
687   bool IsEnabled() override
688   {
689     return mIsEnabled;
690   }
691 }; // BridgeImpl
692
693 namespace // unnamed namespace
694 {
695
696 bool INITIALIZED_BRIDGE = false;
697
698 /**
699  * @brief Creates BridgeImpl instance.
700  *
701  * @return The BridgeImpl instance
702  * @note This method is to check environment variable first. If ATSPI is disable using env, it returns dummy bridge instance.
703  */
704 std::shared_ptr<Bridge> CreateBridge()
705 {
706   INITIALIZED_BRIDGE = true;
707
708   try
709   {
710     /* check environment variable first */
711     const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
712     if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
713     {
714       return Dali::Accessibility::DummyBridge::GetInstance();
715     }
716
717     return std::make_shared<BridgeImpl>();
718   }
719   catch(const std::exception&)
720   {
721     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
722     return Dali::Accessibility::DummyBridge::GetInstance();
723   }
724 }
725
726 } // unnamed namespace
727
728 // Dali::Accessibility::Bridge class implementation
729
730 std::shared_ptr<Bridge> Bridge::GetCurrentBridge()
731 {
732   static std::shared_ptr<Bridge> bridge;
733
734   if(bridge)
735   {
736     return bridge;
737   }
738   else if(mAutoInitState == AutoInitState::ENABLED)
739   {
740     bridge = CreateBridge();
741
742     /* check environment variable for suppressing screen-reader */
743     const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
744     if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
745     {
746       bridge->SuppressScreenReader(true);
747     }
748
749     return bridge;
750   }
751
752   return Dali::Accessibility::DummyBridge::GetInstance();
753 }
754
755 void Bridge::DisableAutoInit()
756 {
757   if(INITIALIZED_BRIDGE)
758   {
759     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
760   }
761
762   mAutoInitState = AutoInitState::DISABLED;
763 }
764
765 void Bridge::EnableAutoInit()
766 {
767   mAutoInitState = AutoInitState::ENABLED;
768
769   if(INITIALIZED_BRIDGE)
770   {
771     return;
772   }
773
774   auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer(); // A root layer of the default window.
775   auto window          = Dali::DevelWindow::Get(rootLayer);
776   auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
777
778   auto accessible = Accessibility::Accessible::Get(rootLayer, true);
779
780   auto bridge = Bridge::GetCurrentBridge();
781   bridge->AddTopLevelWindow(accessible);
782   bridge->SetApplicationName(applicationName);
783   bridge->Initialize();
784
785   if(window && window.IsVisible())
786   {
787     bridge->WindowShown(window);
788   }
789 }