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