c48240cd840bec8bdc9554ec99d457769b2862ba
[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       // The ~Window() after this point cannot emit DESTROY, because Bridge is not available. So emit DESTROY here.
276       for(auto windowAccessible : mApplication.mChildren)
277       {
278         BridgeObject::Emit(windowAccessible, WindowEvent::DESTROY);
279       }
280       mData->mCurrentlyHighlightedActor = {};
281       mData->mHighlightActor            = {};
282     }
283     ForceDown();
284     if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
285     {
286       Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
287     }
288     mAccessibilityStatusClient        = {};
289     mDbusServer                       = {};
290     mConnectionPtr                    = {};
291   }
292
293   bool ForceUpTimerCallback()
294   {
295     if(ForceUp() != ForceUpResult::FAILED)
296     {
297       return false;
298     }
299     return true;
300   }
301
302   /**
303    * @copydoc Dali::Accessibility::Bridge::ForceUp()
304    */
305   ForceUpResult ForceUp() override
306   {
307     auto forceUpResult = BridgeAccessible::ForceUp();
308     if(forceUpResult == ForceUpResult::ALREADY_UP)
309     {
310       return forceUpResult;
311     }
312     else if(forceUpResult == ForceUpResult::FAILED)
313     {
314       if(!mForceUpTimer)
315       {
316         mForceUpTimer = Dali::Timer::New(RETRY_INTERVAL);
317         mForceUpTimer.TickSignal().Connect(this, &BridgeImpl::ForceUpTimerCallback);
318         mForceUpTimer.Start();
319       }
320       return forceUpResult;
321     }
322
323     BridgeObject::RegisterInterfaces();
324     BridgeAccessible::RegisterInterfaces();
325     BridgeComponent::RegisterInterfaces();
326     BridgeCollection::RegisterInterfaces();
327     BridgeAction::RegisterInterfaces();
328     BridgeValue::RegisterInterfaces();
329     BridgeText::RegisterInterfaces();
330     BridgeEditableText::RegisterInterfaces();
331     BridgeSelection::RegisterInterfaces();
332     BridgeApplication::RegisterInterfaces();
333     BridgeHypertext::RegisterInterfaces();
334     BridgeHyperlink::RegisterInterfaces();
335     BridgeSocket::RegisterInterfaces();
336
337     RegisterOnBridge(&mApplication);
338
339     mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
340     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
341
342     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
343       auto it = mDirectReadingCallbacks.find(id);
344       if(it != mDirectReadingCallbacks.end())
345       {
346         it->second(readingState);
347         if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
348         {
349           mDirectReadingCallbacks.erase(it);
350         }
351       }
352     });
353
354     auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
355     Address root{"", "root"};
356     auto    res = proxy.method<Address(Address)>("Embed").call(root);
357     if(!res)
358     {
359       LOG() << "Call to Embed failed: " << res.getError().message;
360     }
361     assert(res);
362
363     mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
364
365     mEnabledSignal.Emit();
366
367     return ForceUpResult::JUST_STARTED;
368   }
369
370   /**
371    * @brief Sends a signal to dbus that the window is shown.
372    *
373    * @param[in] window The window to be shown
374    * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
375    */
376   void EmitShown(Dali::Window window)
377   {
378     auto windowAccessible = mApplication.GetWindowAccessible(window);
379     if(windowAccessible)
380     {
381       windowAccessible->EmitShowing(true);
382     }
383   }
384
385   /**
386    * @brief Sends a signal to dbus that the window is hidden.
387    *
388    * @param[in] window The window to be hidden
389    * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
390    */
391   void EmitHidden(Dali::Window window)
392   {
393     auto windowAccessible = mApplication.GetWindowAccessible(window);
394     if(windowAccessible)
395     {
396       windowAccessible->EmitShowing(false);
397     }
398   }
399
400   /**
401    * @brief Sends a signal to dbus that the window is activated.
402    *
403    * @param[in] window The window to be activated
404    * @see BridgeObject::Emit()
405    */
406   void EmitActivate(Dali::Window window)
407   {
408     auto windowAccessible = mApplication.GetWindowAccessible(window);
409     if(windowAccessible)
410     {
411       windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
412     }
413   }
414
415   /**
416    * @brief Sends a signal to dbus that the window is deactivated.
417    *
418    * @param[in] window The window to be deactivated
419    * @see BridgeObject::Emit()
420    */
421   void EmitDeactivate(Dali::Window window)
422   {
423     auto windowAccessible = mApplication.GetWindowAccessible(window);
424     if(windowAccessible)
425     {
426       windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
427     }
428   }
429
430   /**
431    * @copydoc Dali::Accessibility::Bridge::WindowShown()
432    */
433   void WindowShown(Dali::Window window) override
434   {
435     if(!mIsShown && IsUp())
436     {
437       EmitShown(window);
438     }
439     mIsShown = true;
440   }
441
442   /**
443    * @copydoc Dali::Accessibility::Bridge::WindowHidden()
444    */
445   void WindowHidden(Dali::Window window) override
446   {
447     if(mIsShown && IsUp())
448     {
449       EmitHidden(window);
450     }
451     mIsShown = false;
452   }
453
454   /**
455    * @copydoc Dali::Accessibility::Bridge::WindowFocused()
456    */
457   void WindowFocused(Dali::Window window) override
458   {
459     if(mIsShown && IsUp())
460     {
461       EmitActivate(window);
462     }
463   }
464
465   /**
466    * @copydoc Dali::Accessibility::Bridge::WindowUnfocused()
467    */
468   void WindowUnfocused(Dali::Window window) override
469   {
470     if(mIsShown && IsUp())
471     {
472       EmitDeactivate(window);
473     }
474   }
475
476   /**
477    * @copydoc Dali::Accessibility::Bridge::SuppressScreenReader()
478    */
479   void SuppressScreenReader(bool suppress) override
480   {
481     if(mIsScreenReaderSuppressed == suppress)
482     {
483       return;
484     }
485     mIsScreenReaderSuppressed = suppress;
486     ReadScreenReaderEnabledProperty();
487   }
488
489   void SwitchBridge()
490   {
491     if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
492     {
493       ForceUp();
494     }
495     else
496     {
497       ForceDown();
498     }
499   }
500
501   bool ReadIsEnabledTimerCallback()
502   {
503     ReadIsEnabledProperty();
504     return false;
505   }
506
507   void ReadIsEnabledProperty()
508   {
509     mAccessibilityStatusClient.property<bool>("IsEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
510       if(!msg)
511       {
512         DALI_LOG_ERROR("Get IsEnabled property error: %s\n", msg.getError().message.c_str());
513         if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
514         {
515           if(!mReadIsEnabledTimer)
516           {
517             mReadIsEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
518             mReadIsEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadIsEnabledTimerCallback);
519           }
520           mReadIsEnabledTimer.Start();
521         }
522         return;
523       }
524
525       if(mReadIsEnabledTimer)
526       {
527         mReadIsEnabledTimer.Stop();
528         mReadIsEnabledTimer.Reset();
529       }
530
531       mIsEnabled = std::get<0>(msg);
532       SwitchBridge();
533     });
534   }
535
536   void ListenIsEnabledProperty()
537   {
538     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
539       mIsEnabled = res;
540       SwitchBridge();
541     });
542   }
543
544   bool ReadScreenReaderEnabledTimerCallback()
545   {
546     ReadScreenReaderEnabledProperty();
547     return false;
548   }
549
550   void ReadScreenReaderEnabledProperty()
551   {
552     // can be true because of SuppressScreenReader before init
553     if (!mAccessibilityStatusClient)
554     {
555       return;
556     }
557
558     mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
559       if(!msg)
560       {
561         DALI_LOG_ERROR("Get ScreenReaderEnabled property error: %s\n", msg.getError().message.c_str());
562         if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
563         {
564           if(!mReadScreenReaderEnabledTimer)
565           {
566             mReadScreenReaderEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
567             mReadScreenReaderEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadScreenReaderEnabledTimerCallback);
568           }
569           mReadScreenReaderEnabledTimer.Start();
570         }
571         return;
572       }
573
574       if(mReadScreenReaderEnabledTimer)
575       {
576         mReadScreenReaderEnabledTimer.Stop();
577         mReadScreenReaderEnabledTimer.Reset();
578       }
579
580       mIsScreenReaderEnabled = std::get<0>(msg);
581       SwitchBridge();
582     });
583   }
584
585   void EmitScreenReaderEnabledSignal()
586   {
587     if (mIsScreenReaderEnabled)
588     {
589       mScreenReaderEnabledSignal.Emit();
590     }
591     else
592     {
593       mScreenReaderDisabledSignal.Emit();
594     }
595   }
596
597   void ListenScreenReaderEnabledProperty()
598   {
599     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
600       mIsScreenReaderEnabled = res;
601       EmitScreenReaderEnabledSignal();
602       SwitchBridge();
603     });
604   }
605
606   void ReadAndListenProperties()
607   {
608     ReadIsEnabledProperty();
609     ListenIsEnabledProperty();
610
611     ReadScreenReaderEnabledProperty();
612     ListenScreenReaderEnabledProperty();
613   }
614
615   bool InitializeAccessibilityStatusClient()
616   {
617     mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
618
619     if (!mAccessibilityStatusClient)
620     {
621       DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
622       return false;
623     }
624
625     return true;
626   }
627
628   bool InitializeTimerCallback()
629   {
630     if ( InitializeAccessibilityStatusClient() )
631     {
632       ReadAndListenProperties();
633       return false;
634     }
635     return true;
636   }
637
638   bool OnIdleSignal()
639   {
640     if ( InitializeAccessibilityStatusClient() )
641     {
642       ReadAndListenProperties();
643       mIdleCallback = NULL;
644       return false;
645     }
646
647     if(!mInitializeTimer)
648     {
649       mInitializeTimer = Dali::Timer::New(RETRY_INTERVAL);
650       mInitializeTimer.TickSignal().Connect(this, &BridgeImpl::InitializeTimerCallback);
651     }
652     mInitializeTimer.Start();
653
654     mIdleCallback = NULL;
655     return false;
656   }
657
658   /**
659    * @copydoc Dali::Accessibility::Bridge::Initialize()
660    */
661   void Initialize() override
662   {
663     if ( InitializeAccessibilityStatusClient() )
664     {
665       ReadAndListenProperties();
666       return;
667     }
668
669     // Initialize failed. Try it again on Idle
670     if( Dali::Adaptor::IsAvailable() )
671     {
672       Dali::Adaptor& adaptor = Dali::Adaptor::Get();
673       if( NULL == mIdleCallback )
674       {
675         mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
676         adaptor.AddIdle( mIdleCallback, true );
677       }
678     }
679   }
680
681   /**
682    * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
683    */
684   bool GetScreenReaderEnabled() override
685   {
686     return mIsScreenReaderEnabled;
687   }
688
689   /**
690    * @copydoc Dali::Accessibility::Bridge::IsEnabled()
691    */
692   bool IsEnabled() override
693   {
694     return mIsEnabled;
695   }
696 }; // BridgeImpl
697
698 namespace // unnamed namespace
699 {
700
701 bool INITIALIZED_BRIDGE = false;
702
703 /**
704  * @brief Creates BridgeImpl instance.
705  *
706  * @return The BridgeImpl instance
707  * @note This method is to check environment variable first. If ATSPI is disable using env, it returns dummy bridge instance.
708  */
709 std::shared_ptr<Bridge> CreateBridge()
710 {
711   INITIALIZED_BRIDGE = true;
712
713   try
714   {
715     /* check environment variable first */
716     const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
717     if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
718     {
719       return Dali::Accessibility::DummyBridge::GetInstance();
720     }
721
722     return std::make_shared<BridgeImpl>();
723   }
724   catch(const std::exception&)
725   {
726     DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
727     return Dali::Accessibility::DummyBridge::GetInstance();
728   }
729 }
730
731 } // unnamed namespace
732
733 // Dali::Accessibility::Bridge class implementation
734
735 std::shared_ptr<Bridge> Bridge::GetCurrentBridge()
736 {
737   static std::shared_ptr<Bridge> bridge;
738
739   if(bridge)
740   {
741     return bridge;
742   }
743   else if(mAutoInitState == AutoInitState::ENABLED)
744   {
745     bridge = CreateBridge();
746
747     /* check environment variable for suppressing screen-reader */
748     const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
749     if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
750     {
751       bridge->SuppressScreenReader(true);
752     }
753
754     return bridge;
755   }
756
757   return Dali::Accessibility::DummyBridge::GetInstance();
758 }
759
760 void Bridge::DisableAutoInit()
761 {
762   if(INITIALIZED_BRIDGE)
763   {
764     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
765   }
766
767   mAutoInitState = AutoInitState::DISABLED;
768 }
769
770 void Bridge::EnableAutoInit()
771 {
772   mAutoInitState = AutoInitState::ENABLED;
773
774   if(INITIALIZED_BRIDGE)
775   {
776     return;
777   }
778
779   auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer(); // A root layer of the default window.
780   auto window          = Dali::DevelWindow::Get(rootLayer);
781   auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
782
783   auto accessible = Accessibility::Accessible::Get(rootLayer);
784
785   auto bridge = Bridge::GetCurrentBridge();
786   bridge->AddTopLevelWindow(accessible);
787   bridge->SetApplicationName(applicationName);
788   bridge->Initialize();
789
790   if(window && window.IsVisible())
791   {
792     bridge->WindowShown(window);
793   }
794 }