[Tizen][AT-SPI] do not keep window in ApplicationAccessible
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
index 91f68c8..27525b4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 
 // EXTERNAL INCLUDES
+#include <dali/devel-api/common/stage.h>
 #include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/layer.h>
 #include <iostream>
 #include <unordered_map>
 
 // INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
 #include <dali/internal/accessibility/bridge/bridge-action.h>
 #include <dali/internal/accessibility/bridge/bridge-collection.h>
 #include <dali/internal/accessibility/bridge/bridge-component.h>
+#include <dali/internal/accessibility/bridge/bridge-editable-text.h>
 #include <dali/internal/accessibility/bridge/bridge-object.h>
-#include <dali/internal/accessibility/bridge/bridge-value.h>
+#include <dali/internal/accessibility/bridge/bridge-selection.h>
 #include <dali/internal/accessibility/bridge/bridge-text.h>
-#include <dali/internal/accessibility/bridge/bridge-editable-text.h>
+#include <dali/internal/accessibility/bridge/bridge-value.h>
+#include <dali/internal/accessibility/bridge/bridge-application.h>
+#include <dali/internal/accessibility/bridge/dummy-atspi.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/system/common/environment-variables.h>
 
 using namespace Dali::Accessibility;
 
+namespace // unnamed namespace
+{
+
+const int RETRY_INTERVAL = 1000;
+
+} // unnamed namespace
+
+/**
+ * @brief The BridgeImpl class is to implement some Bridge functions.
+ */
 class BridgeImpl : public virtual BridgeBase,
                    public BridgeAccessible,
                    public BridgeObject,
@@ -42,70 +61,51 @@ class BridgeImpl : public virtual BridgeBase,
                    public BridgeAction,
                    public BridgeValue,
                    public BridgeText,
-                   public BridgeEditableText
+                   public BridgeEditableText,
+                   public BridgeSelection,
+                   public BridgeApplication
 {
-  DBus::DBusClient listenOnAtspiEnabledSignalClient;
-  DBus::DBusClient registryClient, directReadingClient;
-  bool screenReaderEnabled = false;
-  bool isEnabled = false;
-  bool isShown = false;
-  std::unordered_map <int32_t, std::function<void(std::string)>> directReadingCallbacks;
-  Dali::Actor highlightedActor;
-  std::function<void(Dali::Actor)> highlightClearAction;
+  DBus::DBusClient                                              mAccessibilityStatusClient;
+  DBus::DBusClient                                              mRegistryClient;
+  DBus::DBusClient                                              mDirectReadingClient;
+  bool                                                          mIsScreenReaderEnabled = false;
+  bool                                                          mIsEnabled             = false;
+  bool                                                          mIsShown               = false;
+  std::unordered_map<int32_t, std::function<void(std::string)>> mDirectReadingCallbacks;
+  Dali::Actor                                                   mHighlightedActor;
+  std::function<void(Dali::Actor)>                              mHighlightClearAction;
+  Dali::CallbackBase*                                           mIdleCallback          = NULL;
+  Dali::Timer                                                   mInitializeTimer;
+  Dali::Timer                                                   mReadIsEnabledTimer;
+  Dali::Timer                                                   mReadScreenReaderEnabledTimer;
 
 public:
   BridgeImpl()
   {
-    listenOnAtspiEnabledSignalClient = DBus::DBusClient{ A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION };
-
-    listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "ScreenReaderEnabled", [this]( bool res )
-      {
-        screenReaderEnabled = res;
-        if( screenReaderEnabled || isEnabled )
-        {
-          ForceUp();
-        }
-        else
-        {
-          ForceDown();
-        }
-      }
-    );
-
-    listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "IsEnabled", [this]( bool res )
-      {
-        isEnabled = res;
-        if( screenReaderEnabled || isEnabled )
-        {
-          ForceUp();
-        }
-        else
-        {
-          ForceDown();
-        }
-      }
-    );
   }
 
-  Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) override
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Emit()
+   */
+  Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
   {
-    if (!IsUp())
+    if(!IsUp())
     {
       return Consumed::NO;
     }
 
-    unsigned int evType = 0;
+    unsigned int keyType = 0;
 
-    switch( type )
+    switch(type)
     {
       case KeyEventType::KEY_PRESSED:
       {
-        evType = 0;
+        keyType = 0;
         break;
       }
       case KeyEventType::KEY_RELEASED:
       {
-        evType = 1;
+        keyType = 1;
         break;
       }
       default:
@@ -113,107 +113,168 @@ public:
         return Consumed::NO;
       }
     }
-    auto m = registryClient.method< bool( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool > ) >( "NotifyListenersSync" );
-    auto result = m.call( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool >{evType, 0, static_cast< int32_t >( keyCode ), 0, static_cast< int32_t >( timeStamp ), keyName, isText ? 1 : 0} );
-    if( !result )
+
+    auto methodObject = mRegistryClient.method<bool(std::tuple<uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool>)>("NotifyListenersSync");
+    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});
+    if(!result)
     {
       LOG() << result.getError().message;
       return Consumed::NO;
     }
-    return std::get< 0 >( result ) ? Consumed::YES : Consumed::NO;
+    return std::get<0>(result) ? Consumed::YES : Consumed::NO;
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Pause()
+   */
   void Pause() override
   {
-    if (!IsUp())
+    if(!IsUp())
     {
       return;
     }
 
-    directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).asyncCall(
-      []( DBus::ValueOrError< void > msg ) {
-        if (!msg)
-        {
-          LOG() << "Direct reading command failed (" << msg.getError().message << ")";
-        }
-      },
-      true);
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
+      if(!msg)
+      {
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+      }
+    },
+                                                                                        true);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Resume()
+   */
   void Resume() override
   {
-    if (!IsUp())
+    if(!IsUp())
     {
       return;
     }
 
-    directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).asyncCall(
-      []( DBus::ValueOrError< void > msg) {
-        if (!msg)
-        {
-          LOG() << "Direct reading command failed (" << msg.getError().message << ")";
-        }
-      },
-      false);
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
+      if(!msg)
+      {
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+      }
+    },
+                                                                                        false);
   }
 
-  void Say( const std::string& text, bool discardable, std::function< void(std::string) > callback ) override
+  /**
+   * @copydoc Dali::Accessibility::Bridge::StopReading()
+   */
+  void StopReading(bool alsoNonDiscardable) override
   {
-    if (!IsUp())
+    if(!IsUp())
     {
       return;
     }
 
-    directReadingClient.method< DBus::ValueOrError< std::string, bool, int32_t >( std::string, bool ) > ( "ReadCommand" ).asyncCall(
-      [=]( DBus::ValueOrError<std::string, bool, int32_t> msg ) {
-        if ( !msg )
-        {
-          LOG() << "Direct reading command failed (" << msg.getError().message << ")";
-        }
-        else if( callback )
-        {
-          directReadingCallbacks.emplace( std::get< 2 >( msg ), callback);
-        }
-      },
-      text,
-      discardable);
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
+      if(!msg)
+      {
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+      }
+    },
+                                                                                        alsoNonDiscardable);
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Say()
+   */
+  void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
+  {
+    if(!IsUp())
+    {
+      return;
+    }
+
+    mDirectReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
+      if(!msg)
+      {
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+      }
+      else if(callback)
+      {
+        mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
+      }
+    },
+                                                                                                                           text,
+                                                                                                                           discardable);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::ForceDown()
+   */
   void ForceDown() override
   {
-    if (data)
+    if(mData)
     {
-      if (data->currentlyHighlightedActor && data->highlightActor)
+      if(mData->mCurrentlyHighlightedActor && mData->mHighlightActor)
       {
-        data->currentlyHighlightedActor.Remove(data->highlightActor);
+        mData->mCurrentlyHighlightedActor.Remove(mData->mHighlightActor);
       }
-      data->currentlyHighlightedActor = {};
-      data->highlightActor = {};
+      mData->mCurrentlyHighlightedActor = {};
+      mData->mHighlightActor            = {};
+
+      mDisabledSignal.Emit();
     }
-    highlightedActor = {};
-    highlightClearAction = {};
+    mHighlightedActor     = {};
+    mHighlightClearAction = {};
     BridgeAccessible::ForceDown();
-    registryClient = {};
-    directReadingClient = {};
-    directReadingCallbacks.clear();
+    mRegistryClient       = {};
+    mDirectReadingClient  = {};
+    mDirectReadingCallbacks.clear();
+    mApplication.mChildren.clear();
+  }
+
+  void StopTimer()
+  {
+    if(mInitializeTimer)
+    {
+      mInitializeTimer.Stop();
+    }
+
+    if(mReadIsEnabledTimer)
+    {
+      mReadIsEnabledTimer.Stop();
+    }
+
+    if(mReadScreenReaderEnabledTimer)
+    {
+      mReadScreenReaderEnabledTimer.Stop();
+    }
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Terminate()
+   */
   void Terminate() override
   {
-    if (data)
+    if(mData)
     {
-      data->currentlyHighlightedActor = {};
-      data->highlightActor = {};
+      mData->mCurrentlyHighlightedActor = {};
+      mData->mHighlightActor            = {};
     }
     ForceDown();
-    listenOnAtspiEnabledSignalClient = {};
-    dbusServer = {};
-    con = {};
+    StopTimer();
+    if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
+    {
+      Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
+    }
+    mAccessibilityStatusClient        = {};
+    mDbusServer                       = {};
+    mConnectionPtr                    = {};
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::ForceUp()
+   */
   ForceUpResult ForceUp() override
   {
-    if( BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP )
+    if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
     {
       return ForceUpResult::ALREADY_UP;
     }
@@ -226,109 +287,453 @@ public:
     BridgeValue::RegisterInterfaces();
     BridgeText::RegisterInterfaces();
     BridgeEditableText::RegisterInterfaces();
+    BridgeSelection::RegisterInterfaces();
+    BridgeApplication::RegisterInterfaces();
+
+    RegisterOnBridge(&mApplication);
 
-    RegisterOnBridge( &application );
+    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+    mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
 
-    registryClient = { AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con };
-    directReadingClient = DBus::DBusClient{ DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con };
-    directReadingClient.addSignal< void(int32_t, std::string) >( "ReadingStateChanged", [=]( int32_t id, std::string readingState )
+    mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
+      auto it = mDirectReadingCallbacks.find(id);
+      if(it != mDirectReadingCallbacks.end())
       {
-        auto it = directReadingCallbacks.find( id );
-        if (it != directReadingCallbacks.end())
+        it->second(readingState);
+        if(readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
         {
-          it->second( readingState );
-          if (readingState != "ReadingPaused" && readingState != "ReadingResumed" && readingState != "ReadingStarted")
-            directReadingCallbacks.erase( it );
+          mDirectReadingCallbacks.erase(it);
         }
       }
-    );
+    });
 
-    auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con};
+    auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
     Address root{"", "root"};
-    auto res = proxy.method< Address( Address ) >( "Embed" ).call( root );
-    if (!res)
+    auto    res = proxy.method<Address(Address)>("Embed").call(root);
+    if(!res)
     {
       LOG() << "Call to Embed failed: " << res.getError().message;
     }
-    assert( res );
-    application.parent.SetAddress( std::move( std::get< 0 >( res ) ) );
-    if (isShown)
+    assert(res);
+
+    mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
+
+    mEnabledSignal.Emit();
+
+    return ForceUpResult::JUST_STARTED;
+  }
+
+  /**
+   * @brief Sends a signal to dbus that the window is shown.
+   *
+   * @param[in] window The window to be shown
+   * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
+   */
+  void EmitShown(Dali::Window window)
+  {
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      EmitActivate();
+      windowAccessible->EmitShowing(true);
     }
-    return ForceUpResult::JUST_STARTED;
   }
 
-  void EmitActivate()
+  /**
+   * @brief Sends a signal to dbus that the window is hidden.
+   *
+   * @param[in] window The window to be hidden
+   * @see Accessible::EmitShowing() and BridgeObject::EmitStateChanged()
+   */
+  void EmitHidden(Dali::Window window)
   {
-    auto win = application.getActiveWindow();
-    if (win)
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      win->Emit( WindowEvent::ACTIVATE, 0 );
+      windowAccessible->EmitShowing(false);
     }
   }
 
-  void EmitDeactivate()
+  /**
+   * @brief Sends a signal to dbus that the window is activated.
+   *
+   * @param[in] window The window to be activated
+   * @see BridgeObject::Emit()
+   */
+  void EmitActivate(Dali::Window window)
   {
-    auto win = application.getActiveWindow();
-    if (win)
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      win->Emit( WindowEvent::DEACTIVATE, 0 );
+      windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
     }
   }
 
-  void ApplicationHidden() override
+  /**
+   * @brief Sends a signal to dbus that the window is deactivated.
+   *
+   * @param[in] window The window to be deactivated
+   * @see BridgeObject::Emit()
+   */
+  void EmitDeactivate(Dali::Window window)
   {
-    if ( isShown && IsUp() )
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      EmitDeactivate();
+      windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
     }
-    isShown = false;
   }
 
-  void ApplicationShown() override
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowShown()
+   */
+  void WindowShown(Dali::Window window) override
   {
-    if ( !isShown && IsUp() )
+    if(!mIsShown && IsUp())
     {
-      EmitActivate();
+      EmitShown(window);
     }
-    isShown = true;
+    mIsShown = true;
   }
 
-  void Initialize() override
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowHidden()
+   */
+  void WindowHidden(Dali::Window window) override
+  {
+    if(mIsShown && IsUp())
+    {
+      EmitHidden(window);
+    }
+    mIsShown = false;
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowFocused()
+   */
+  void WindowFocused(Dali::Window window) override
+  {
+    if(mIsShown && IsUp())
+    {
+      EmitActivate(window);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowUnfocused()
+   */
+  void WindowUnfocused(Dali::Window window) override
+  {
+    if(mIsShown && IsUp())
+    {
+      EmitDeactivate(window);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::SuppressScreenReader()
+   */
+  void SuppressScreenReader(bool suppress) override
+  {
+    if(mIsScreenReaderSuppressed == suppress)
+    {
+      return;
+    }
+    mIsScreenReaderSuppressed = suppress;
+    ReadScreenReaderEnabledProperty();
+  }
+
+  bool ReadIsEnabledTimerCallback()
+  {
+    ReadIsEnabledProperty();
+    return false;
+  }
+
+  void ReadIsEnabledProperty()
+  {
+    mAccessibilityStatusClient.property<bool>("IsEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
+      if(!msg)
+      {
+        DALI_LOG_ERROR("Get IsEnabled property error: %s\n", msg.getError().message.c_str());
+        if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
+        {
+          if(!mReadIsEnabledTimer)
+          {
+            mReadIsEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
+            mReadIsEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadIsEnabledTimerCallback);
+          }
+          mReadIsEnabledTimer.Start();
+        }
+        return;
+      }
+      mIsEnabled = std::get<0>(msg);
+      if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+  }
+
+  void ListenIsEnabledProperty()
+  {
+    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
+      mIsEnabled = res;
+      if(mIsScreenReaderEnabled || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+  }
+
+  bool ReadScreenReaderEnabledTimerCallback()
+  {
+    ReadScreenReaderEnabledProperty();
+    return false;
+  }
+
+  void ReadScreenReaderEnabledProperty()
+  {
+    // can be true because of SuppressScreenReader before init
+    if (!mAccessibilityStatusClient)
+    {
+      return;
+    }
+
+    mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
+      if(!msg)
+      {
+        DALI_LOG_ERROR("Get ScreenReaderEnabled property error: %s\n", msg.getError().message.c_str());
+        if(msg.getError().errorType == DBus::ErrorType::INVALID_REPLY)
+        {
+          if(!mReadScreenReaderEnabledTimer)
+          {
+            mReadScreenReaderEnabledTimer = Dali::Timer::New(RETRY_INTERVAL);
+            mReadScreenReaderEnabledTimer.TickSignal().Connect(this, &BridgeImpl::ReadScreenReaderEnabledTimerCallback);
+          }
+          mReadScreenReaderEnabledTimer.Start();
+        }
+        return;
+      }
+      mIsScreenReaderEnabled = std::get<0>(msg);
+      if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+  }
+
+  void ListenScreenReaderEnabledProperty()
   {
-    auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
-    auto p = req.property< bool >( "ScreenReaderEnabled" ).get();
-    if( p )
+    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
+      mIsScreenReaderEnabled = res;
+      if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+  }
+
+  void ReadAndListenProperties()
+  {
+    ReadIsEnabledProperty();
+    ListenIsEnabledProperty();
+
+    ReadScreenReaderEnabledProperty();
+    ListenScreenReaderEnabledProperty();
+  }
+
+  bool InitializeAccessibilityStatusClient()
+  {
+    mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
+
+    if (!mAccessibilityStatusClient)
+    {
+      DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
+      return false;
+    }
+
+    return true;
+  }
+
+  bool InitializeTimerCallback()
+  {
+    if ( InitializeAccessibilityStatusClient() )
+    {
+      ReadAndListenProperties();
+      return false;
+    }
+    return true;
+  }
+
+  bool OnIdleSignal()
+  {
+    if ( InitializeAccessibilityStatusClient() )
+    {
+      ReadAndListenProperties();
+      mIdleCallback = NULL;
+      return false;
+    }
+
+    if(!mInitializeTimer)
     {
-      screenReaderEnabled = std::get< 0 >( p );
+      mInitializeTimer = Dali::Timer::New(RETRY_INTERVAL);
+      mInitializeTimer.TickSignal().Connect(this, &BridgeImpl::InitializeTimerCallback);
     }
-    p = req.property< bool >( "IsEnabled" ).get();
-    if( p )
+    mInitializeTimer.Start();
+
+    mIdleCallback = NULL;
+    return false;
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Initialize()
+   */
+  void Initialize() override
+  {
+    if ( InitializeAccessibilityStatusClient() )
     {
-      isEnabled = std::get< 0 >( p );
+      ReadAndListenProperties();
+      return;
     }
-    if( screenReaderEnabled || isEnabled )
+
+    // Initialize failed. Try it again on Idle
+    if( Dali::Adaptor::IsAvailable() )
     {
-      ForceUp();
+      Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+      if( NULL == mIdleCallback )
+      {
+        mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
+        adaptor.AddIdle( mIdleCallback, true );
+      }
     }
   }
 
-  bool GetScreenReaderEnabled()
+  /**
+   * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
+   */
+  bool GetScreenReaderEnabled() override
   {
-    return screenReaderEnabled;
+    return mIsScreenReaderEnabled;
   }
 
-  bool GetIsEnabled()
+  /**
+   * @copydoc Dali::Accessibility::Bridge::IsEnabled()
+   */
+  bool IsEnabled() override
   {
-    return isEnabled;
+    return mIsEnabled;
   }
+}; // BridgeImpl
+
+namespace // unnamed namespace
+{
 
-};
+bool INITIALIZED_BRIDGE = false;
+
+/**
+ * @brief Creates BridgeImpl instance.
+ *
+ * @return The BridgeImpl instance
+ * @note This method is to check environment variable first. If ATSPI is disable using env, it returns dummy bridge instance.
+ */
+Bridge* CreateBridge()
+{
+  INITIALIZED_BRIDGE = true;
+
+  try
+  {
+    /* check environment variable first */
+    const char* envAtspiDisabled = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_DISABLE_ATSPI);
+    if(envAtspiDisabled && std::atoi(envAtspiDisabled) != 0)
+    {
+      return Dali::Accessibility::DummyBridge::GetInstance();
+    }
+
+    return new BridgeImpl;
+  }
+  catch(const std::exception&)
+  {
+    DALI_LOG_ERROR("Failed to initialize AT-SPI bridge");
+    return Dali::Accessibility::DummyBridge::GetInstance();
+  }
+}
+
+} // unnamed namespace
+
+// Dali::Accessibility::Bridge class implementation
 
 Bridge* Bridge::GetCurrentBridge()
 {
-  static BridgeImpl *bridge = new BridgeImpl;
-  return bridge;
+  static Bridge* bridge;
+
+  if(bridge)
+  {
+    return bridge;
+  }
+  else if(mAutoInitState == AutoInitState::ENABLED)
+  {
+    bridge = CreateBridge();
+
+    /* check environment variable for suppressing screen-reader */
+    const char* envSuppressScreenReader = Dali::EnvironmentVariable::GetEnvironmentVariable(DALI_ENV_SUPPRESS_SCREEN_READER);
+    if(envSuppressScreenReader && std::atoi(envSuppressScreenReader) != 0)
+    {
+      bridge->SuppressScreenReader(true);
+    }
+
+    return bridge;
+  }
+
+  return Dali::Accessibility::DummyBridge::GetInstance();
+}
+
+void Bridge::DisableAutoInit()
+{
+  if(INITIALIZED_BRIDGE)
+  {
+    DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
+  }
+
+  mAutoInitState = AutoInitState::DISABLED;
 }
 
+void Bridge::EnableAutoInit()
+{
+  mAutoInitState = AutoInitState::ENABLED;
+
+  if(INITIALIZED_BRIDGE)
+  {
+    return;
+  }
+
+  auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer(); // A root layer of the default window.
+  auto window          = Dali::DevelWindow::Get(rootLayer);
+  auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName();
+
+  auto accessible = Accessibility::Accessible::Get(rootLayer, true);
+
+  auto* bridge = Bridge::GetCurrentBridge();
+  bridge->AddTopLevelWindow(accessible);
+  bridge->SetApplicationName(applicationName);
+  bridge->Initialize();
+
+  if(window && window.IsVisible())
+  {
+    bridge->WindowShown(window);
+  }
+}