[AT-SPI] Add Table and TableCell interfaces
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
index a4144ab..f76a0ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2022 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.
 // 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/accessibility-common.h>
 #include <dali/internal/accessibility/bridge/bridge-accessible.h>
 #include <dali/internal/accessibility/bridge/bridge-action.h>
+#include <dali/internal/accessibility/bridge/bridge-application.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-hyperlink.h>
+#include <dali/internal/accessibility/bridge/bridge-hypertext.h>
 #include <dali/internal/accessibility/bridge/bridge-object.h>
 #include <dali/internal/accessibility/bridge/bridge-selection.h>
+#include <dali/internal/accessibility/bridge/bridge-socket.h>
+#include <dali/internal/accessibility/bridge/bridge-table.h>
+#include <dali/internal/accessibility/bridge/bridge-table-cell.h>
 #include <dali/internal/accessibility/bridge/bridge-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/accessibility/bridge/dummy/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.
  */
@@ -56,23 +68,30 @@ class BridgeImpl : public virtual BridgeBase,
                    public BridgeText,
                    public BridgeEditableText,
                    public BridgeSelection,
-                   public BridgeApplication
+                   public BridgeApplication,
+                   public BridgeHypertext,
+                   public BridgeHyperlink,
+                   public BridgeSocket,
+                   public BridgeTable,
+                   public BridgeTableCell
 {
-  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;
+  DBus::DBusClient                                              mAccessibilityStatusClient{};
+  DBus::DBusClient                                              mRegistryClient{};
+  DBus::DBusClient                                              mDirectReadingClient{};
+  bool                                                          mIsScreenReaderEnabled{false};
+  bool                                                          mIsEnabled{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;
+  std::function<void(Dali::Actor)>                              mHighlightClearAction{nullptr};
+  Dali::CallbackBase*                                           mIdleCallback{};
+  Dali::Timer                                                   mInitializeTimer;
+  Dali::Timer                                                   mReadIsEnabledTimer;
+  Dali::Timer                                                   mReadScreenReaderEnabledTimer;
+  Dali::Timer                                                   mForceUpTimer;
+  std::string                                                   mPreferredBusName;
 
 public:
-  BridgeImpl()
-  {
-  }
+  BridgeImpl() = default;
 
   /**
    * @copydoc Dali::Accessibility::Bridge::Emit()
@@ -127,10 +146,10 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
-                                                                                        true);
+                                                                                         true);
   }
 
   /**
@@ -146,10 +165,10 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
-                                                                                        false);
+                                                                                         false);
   }
 
   /**
@@ -165,10 +184,10 @@ public:
     mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
-        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
     },
-                                                                                        alsoNonDiscardable);
+                                                                                         alsoNonDiscardable);
   }
 
   /**
@@ -184,15 +203,15 @@ public:
     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 << ")";
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")\n";
       }
       else if(callback)
       {
         mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
       }
     },
-                                                                                                                           text,
-                                                                                                                           discardable);
+                                                                                                                            text,
+                                                                                                                            discardable);
   }
 
   /**
@@ -208,13 +227,47 @@ public:
       }
       mData->mCurrentlyHighlightedActor = {};
       mData->mHighlightActor            = {};
+
+      mDisabledSignal.Emit();
+      UnembedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
+      ReleaseBusName(mPreferredBusName);
     }
+
     mHighlightedActor     = {};
     mHighlightClearAction = {};
     BridgeAccessible::ForceDown();
-    mRegistryClient       = {};
-    mDirectReadingClient  = {};
+    mRegistryClient      = {};
+    mDirectReadingClient = {};
     mDirectReadingCallbacks.clear();
+    mApplication.mChildren.clear();
+    ClearTimer();
+  }
+
+  void ClearTimer()
+  {
+    if(mInitializeTimer)
+    {
+      mInitializeTimer.Stop();
+      mInitializeTimer.Reset();
+    }
+
+    if(mReadIsEnabledTimer)
+    {
+      mReadIsEnabledTimer.Stop();
+      mReadIsEnabledTimer.Reset();
+    }
+
+    if(mReadScreenReaderEnabledTimer)
+    {
+      mReadScreenReaderEnabledTimer.Stop();
+      mReadScreenReaderEnabledTimer.Reset();
+    }
+
+    if(mForceUpTimer)
+    {
+      mForceUpTimer.Stop();
+      mForceUpTimer.Reset();
+    }
   }
 
   /**
@@ -224,6 +277,11 @@ public:
   {
     if(mData)
     {
+      // The ~Window() after this point cannot emit DESTROY, because Bridge is not available. So emit DESTROY here.
+      for(auto windowAccessible : mApplication.mChildren)
+      {
+        BridgeObject::Emit(windowAccessible, WindowEvent::DESTROY);
+      }
       mData->mCurrentlyHighlightedActor = {};
       mData->mHighlightActor            = {};
     }
@@ -232,9 +290,18 @@ public:
     {
       Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
     }
-    mAccessibilityStatusClient        = {};
-    mDbusServer                       = {};
-    mConnectionPtr                    = {};
+    mAccessibilityStatusClient = {};
+    mDbusServer                = {};
+    mConnectionPtr             = {};
+  }
+
+  bool ForceUpTimerCallback()
+  {
+    if(ForceUp() != ForceUpResult::FAILED)
+    {
+      return false;
+    }
+    return true;
   }
 
   /**
@@ -242,9 +309,20 @@ public:
    */
   ForceUpResult ForceUp() override
   {
-    if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
+    auto forceUpResult = BridgeAccessible::ForceUp();
+    if(forceUpResult == ForceUpResult::ALREADY_UP)
+    {
+      return forceUpResult;
+    }
+    else if(forceUpResult == ForceUpResult::FAILED)
     {
-      return ForceUpResult::ALREADY_UP;
+      if(!mForceUpTimer)
+      {
+        mForceUpTimer = Dali::Timer::New(RETRY_INTERVAL);
+        mForceUpTimer.TickSignal().Connect(this, &BridgeImpl::ForceUpTimerCallback);
+        mForceUpTimer.Start();
+      }
+      return forceUpResult;
     }
 
     BridgeObject::RegisterInterfaces();
@@ -257,10 +335,15 @@ public:
     BridgeEditableText::RegisterInterfaces();
     BridgeSelection::RegisterInterfaces();
     BridgeApplication::RegisterInterfaces();
+    BridgeHypertext::RegisterInterfaces();
+    BridgeHyperlink::RegisterInterfaces();
+    BridgeSocket::RegisterInterfaces();
+    BridgeTable::RegisterInterfaces();
+    BridgeTableCell::RegisterInterfaces();
 
     RegisterOnBridge(&mApplication);
 
-    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, Accessible::GetInterfaceName(AtspiInterface::DEVICE_EVENT_CONTROLLER), mConnectionPtr};
     mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
 
     mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
@@ -275,128 +358,342 @@ public:
       }
     });
 
-    auto    proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, mConnectionPtr};
-    Address root{"", "root"};
-    auto    res = proxy.method<Address(Address)>("Embed").call(root);
-    if(!res)
+    RequestBusName(mPreferredBusName);
+
+    auto parentAddress = EmbedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"});
+    mApplication.mParent.SetAddress(std::move(parentAddress));
+    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)
     {
-      LOG() << "Call to Embed failed: " << res.getError().message;
+      windowAccessible->EmitShowing(true);
     }
-    assert(res);
+  }
 
-    mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
-    if(mIsShown)
+  /**
+   * @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 windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      EmitActivate();
+      windowAccessible->EmitShowing(false);
     }
-    return ForceUpResult::JUST_STARTED;
   }
 
   /**
-   * @brief Sends a signal to dbus that the default window is activated.
+   * @brief Sends a signal to dbus that the window is activated.
    *
-   * TODO : This is subject to change if/when we implement multi-window support.
+   * @param[in] window The window to be activated
    * @see BridgeObject::Emit()
    */
-  void EmitActivate()
+  void EmitActivate(Dali::Window window)
   {
-    auto win = mApplication.GetActiveWindow();
-    if(win)
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      win->Emit(WindowEvent::ACTIVATE, 0);
+      windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
     }
   }
 
   /**
-   * @brief Sends a signal to dbus that the default window is deactivated.
+   * @brief Sends a signal to dbus that the window is deactivated.
    *
-   * TODO : This is subject to change if/when we implement multi-window support.
+   * @param[in] window The window to be deactivated
    * @see BridgeObject::Emit()
    */
-  void EmitDeactivate()
+  void EmitDeactivate(Dali::Window window)
   {
-    auto win = mApplication.GetActiveWindow();
-    if(win)
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      win->Emit(WindowEvent::DEACTIVATE, 0);
+      windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
     }
   }
 
   /**
-   * @copydoc Dali::Accessibility::Bridge::WindowHidden()
+   * @brief Sends a signal to dbus that the window is minimized.
+   *
+   * @param[in] window The window to be minimized
+   * @see BridgeObject::Emit()
+   */
+  void EmitMinimize(Dali::Window window)
+  {
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
+    {
+      windowAccessible->Emit(WindowEvent::MINIMIZE, 0);
+    }
+  }
+
+  /**
+   * @brief Sends a signal to dbus that the window is restored.
+   *
+   * @param[in] window The window to be restored
+   * @param[in] detail Restored window state
+   * @see BridgeObject::Emit()
+   */
+  void EmitRestore(Dali::Window window, Dali::Accessibility::WindowRestoreType detail)
+  {
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
+    {
+      windowAccessible->Emit(WindowEvent::RESTORE, static_cast<unsigned int>(detail));
+    }
+  }
+
+  /**
+   * @brief Sends a signal to dbus that the window is maximized.
+   *
+   * @param[in] window The window to be maximized
+   * @see BridgeObject::Emit()
    */
-  void WindowHidden() override
+  void EmitMaximize(Dali::Window window)
   {
-    if(mIsShown && IsUp())
+    auto windowAccessible = mApplication.GetWindowAccessible(window);
+    if(windowAccessible)
     {
-      EmitDeactivate();
+      windowAccessible->Emit(WindowEvent::MAXIMIZE, 0);
     }
-    mIsShown = false;
   }
 
   /**
    * @copydoc Dali::Accessibility::Bridge::WindowShown()
    */
-  void WindowShown() override
+  void WindowShown(Dali::Window window) override
   {
-    if(!mIsShown && IsUp())
+    if(IsUp())
     {
-      EmitActivate();
+      EmitShown(window);
     }
-    mIsShown = true;
   }
 
-  void ReadAndListenProperty()
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowHidden()
+   */
+  void WindowHidden(Dali::Window window) override
   {
-    // read property
-    auto enabled = mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").get();
-    if(enabled)
+    if(IsUp())
     {
-      mIsScreenReaderEnabled = std::get<0>(enabled);
+      EmitHidden(window);
     }
+  }
 
-    enabled = mAccessibilityStatusClient.property<bool>("IsEnabled").get();
-    if(enabled)
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowFocused()
+   */
+  void WindowFocused(Dali::Window window) override
+  {
+    if(IsUp())
     {
-      mIsEnabled = std::get<0>(enabled);
+      EmitActivate(window);
     }
+  }
 
-    if(mIsScreenReaderEnabled || mIsEnabled)
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowUnfocused()
+   */
+  void WindowUnfocused(Dali::Window window) override
+  {
+    if(IsUp())
+    {
+      EmitDeactivate(window);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowMinimized()
+   */
+  void WindowMinimized(Dali::Window window) override
+  {
+    if(IsUp())
+    {
+      EmitMinimize(window);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowRestored()
+   */
+  void WindowRestored(Dali::Window window, WindowRestoreType detail) override
+  {
+    if(IsUp())
+    {
+      EmitRestore(window, detail);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowMaximized()
+   */
+  void WindowMaximized(Dali::Window window) override
+  {
+    if(IsUp())
+    {
+      EmitMaximize(window);
+    }
+  }
+
+  /**
+   * @copydoc Dali::Accessibility::Bridge::SuppressScreenReader()
+   */
+  void SuppressScreenReader(bool suppress) override
+  {
+    if(mIsScreenReaderSuppressed == suppress)
+    {
+      return;
+    }
+    mIsScreenReaderSuppressed = suppress;
+    ReadScreenReaderEnabledProperty();
+  }
+
+  void SwitchBridge()
+  {
+    if((!mIsScreenReaderSuppressed && mIsScreenReaderEnabled) || mIsEnabled)
     {
       ForceUp();
     }
+    else
+    {
+      ForceDown();
+    }
+  }
 
-    // listen property change
-    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
-      mIsScreenReaderEnabled = res;
-      if(mIsScreenReaderEnabled || mIsEnabled)
+  bool ReadIsEnabledTimerCallback()
+  {
+    ReadIsEnabledProperty();
+    return false;
+  }
+
+  void ReadIsEnabledProperty()
+  {
+    mAccessibilityStatusClient.property<bool>("IsEnabled").asyncGet([this](DBus::ValueOrError<bool> msg) {
+      if(!msg)
       {
-        ForceUp();
+        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;
       }
-      else
+
+      if(mReadIsEnabledTimer)
       {
-        ForceDown();
+        mReadIsEnabledTimer.Stop();
+        mReadIsEnabledTimer.Reset();
       }
+
+      mIsEnabled = std::get<0>(msg);
+      SwitchBridge();
     });
+  }
 
+  void ListenIsEnabledProperty()
+  {
     mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
       mIsEnabled = res;
-      if(mIsScreenReaderEnabled || mIsEnabled)
+      SwitchBridge();
+    });
+  }
+
+  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)
       {
-        ForceUp();
+        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;
       }
-      else
+
+      if(mReadScreenReaderEnabledTimer)
       {
-        ForceDown();
+        mReadScreenReaderEnabledTimer.Stop();
+        mReadScreenReaderEnabledTimer.Reset();
       }
+
+      mIsScreenReaderEnabled = std::get<0>(msg);
+      SwitchBridge();
     });
   }
 
+  void EmitScreenReaderEnabledSignal()
+  {
+    if(mIsScreenReaderEnabled)
+    {
+      mScreenReaderEnabledSignal.Emit();
+    }
+    else
+    {
+      mScreenReaderDisabledSignal.Emit();
+    }
+  }
+
+  void ListenScreenReaderEnabledProperty()
+  {
+    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
+      mIsScreenReaderEnabled = res;
+      EmitScreenReaderEnabledSignal();
+      SwitchBridge();
+    });
+  }
+
+  void ReadAndListenProperties()
+  {
+    ReadIsEnabledProperty();
+    ListenIsEnabledProperty();
+
+    ReadScreenReaderEnabledProperty();
+    ListenScreenReaderEnabledProperty();
+  }
+
   bool InitializeAccessibilityStatusClient()
   {
     mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
 
-    if (!mAccessibilityStatusClient)
+    if(!mAccessibilityStatusClient)
     {
       DALI_LOG_ERROR("Accessibility Status DbusClient is not ready\n");
       return false;
@@ -405,16 +702,34 @@ public:
     return true;
   }
 
+  bool InitializeTimerCallback()
+  {
+    if(InitializeAccessibilityStatusClient())
+    {
+      ReadAndListenProperties();
+      return false;
+    }
+    return true;
+  }
+
   bool OnIdleSignal()
   {
-    if ( InitializeAccessibilityStatusClient() )
+    if(InitializeAccessibilityStatusClient())
     {
-      ReadAndListenProperty();
+      ReadAndListenProperties();
       mIdleCallback = NULL;
       return false;
     }
 
-    return true;
+    if(!mInitializeTimer)
+    {
+      mInitializeTimer = Dali::Timer::New(RETRY_INTERVAL);
+      mInitializeTimer.TickSignal().Connect(this, &BridgeImpl::InitializeTimerCallback);
+    }
+    mInitializeTimer.Start();
+
+    mIdleCallback = NULL;
+    return false;
   }
 
   /**
@@ -422,20 +737,20 @@ public:
    */
   void Initialize() override
   {
-    if ( InitializeAccessibilityStatusClient() )
+    if(InitializeAccessibilityStatusClient())
     {
-      ReadAndListenProperty();
+      ReadAndListenProperties();
       return;
     }
 
     // Initialize failed. Try it again on Idle
-    if( Dali::Adaptor::IsAvailable() )
+    if(Dali::Adaptor::IsAvailable())
     {
       Dali::Adaptor& adaptor = Dali::Adaptor::Get();
-      if( NULL == mIdleCallback )
+      if(NULL == mIdleCallback)
       {
-        mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
-        adaptor.AddIdle( mIdleCallback, true );
+        mIdleCallback = MakeCallback(this, &BridgeImpl::OnIdleSignal);
+        adaptor.AddIdle(mIdleCallback, true);
       }
     }
   }
@@ -455,11 +770,99 @@ public:
   {
     return mIsEnabled;
   }
+
+  Address EmbedSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+    auto reply  = client.method<Address(Address)>("Embed").call(plug);
+
+    if(!reply)
+    {
+      DALI_LOG_ERROR("Failed to embed socket %s: %s", socket.ToString().c_str(), reply.getError().message.c_str());
+      return {};
+    }
+
+    return std::get<0>(reply.getValues());
+  }
+
+  void EmbedAtkSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+
+    client.method<void(std::string)>("Embedded").asyncCall([](DBus::ValueOrError<void>) {}, ATSPI_PREFIX_PATH + plug.GetPath());
+  }
+
+  void UnembedSocket(const Address& plug, const Address& socket) override
+  {
+    auto client = CreateSocketClient(socket);
+
+    client.method<void(Address)>("Unembed").asyncCall([](DBus::ValueOrError<void>) {}, plug);
+  }
+
+  void SetSocketOffset(ProxyAccessible* socket, std::int32_t x, std::int32_t y) override
+  {
+    AddCoalescableMessage(CoalescableMessages::SET_OFFSET, socket, 1.0f, [=]() {
+      auto client = CreateSocketClient(socket->GetAddress());
+
+      client.method<void(std::int32_t, std::int32_t)>("SetOffset").asyncCall([](DBus::ValueOrError<void>) {}, x, y);
+    });
+  }
+
+  void SetExtentsOffset(std::int32_t x, std::int32_t y) override
+  {
+    if(mData)
+    {
+      mData->mExtentsOffset = {x, y};
+    }
+  }
+
+  void SetPreferredBusName(std::string_view preferredBusName) override
+  {
+    if(preferredBusName == mPreferredBusName)
+    {
+      return;
+    }
+
+    std::string oldPreferredBusName = std::move(mPreferredBusName);
+    mPreferredBusName               = std::string{preferredBusName};
+
+    if(IsUp())
+    {
+      ReleaseBusName(oldPreferredBusName);
+      RequestBusName(mPreferredBusName);
+    }
+    // else: request/release will be handled by ForceUp/ForceDown, respectively
+  }
+
+private:
+  DBus::DBusClient CreateSocketClient(const Address& socket)
+  {
+    return {socket.GetBus(), ATSPI_PREFIX_PATH + socket.GetPath(), Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr};
+  }
+
+  void RequestBusName(const std::string& busName)
+  {
+    if(busName.empty())
+    {
+      return;
+    }
+
+    DBus::requestBusName(mConnectionPtr, busName);
+  }
+
+  void ReleaseBusName(const std::string& busName)
+  {
+    if(busName.empty())
+    {
+      return;
+    }
+
+    DBus::releaseBusName(mConnectionPtr, busName);
+  }
 }; // BridgeImpl
 
 namespace // unnamed namespace
 {
-
 bool INITIALIZED_BRIDGE = false;
 
 /**
@@ -468,7 +871,7 @@ bool INITIALIZED_BRIDGE = false;
  * @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()
+std::shared_ptr<Bridge> CreateBridge()
 {
   INITIALIZED_BRIDGE = true;
 
@@ -481,7 +884,7 @@ Bridge* CreateBridge()
       return Dali::Accessibility::DummyBridge::GetInstance();
     }
 
-    return new BridgeImpl;
+    return std::make_shared<BridgeImpl>();
   }
   catch(const std::exception&)
   {
@@ -494,9 +897,9 @@ Bridge* CreateBridge()
 
 // Dali::Accessibility::Bridge class implementation
 
-Bridge* Bridge::GetCurrentBridge()
+std::shared_ptr<Bridge> Bridge::GetCurrentBridge()
 {
-  static Bridge* bridge;
+  static std::shared_ptr<Bridge> bridge;
 
   if(bridge)
   {
@@ -538,17 +941,39 @@ void Bridge::EnableAutoInit()
     return;
   }
 
-  auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer();
+  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* bridge = Bridge::GetCurrentBridge();
-  bridge->AddTopLevelWindow(Dali::Accessibility::Accessible::Get(rootLayer, true));
+  auto accessible = Accessibility::Accessible::Get(rootLayer);
+
+  auto bridge = Bridge::GetCurrentBridge();
+  bridge->AddTopLevelWindow(accessible);
   bridge->SetApplicationName(applicationName);
   bridge->Initialize();
 
   if(window && window.IsVisible())
   {
-    bridge->WindowShown();
+    bridge->WindowShown(window);
   }
 }
+
+std::string Bridge::MakeBusNameForWidget(std::string_view widgetInstanceId)
+{
+  // The bus name should consist of dot-separated alphanumeric elements, e.g. "com.example.BusName123".
+  // Allowed characters in each element: "[A-Z][a-z][0-9]_", but no element may start with a digit.
+
+  static const char prefix[]   = "com.samsung.dali.widget_";
+  static const char underscore = '_';
+
+  std::stringstream tmp;
+
+  tmp << prefix;
+
+  for(char ch : widgetInstanceId)
+  {
+    tmp << (std::isalnum(ch) ? ch : underscore);
+  }
+
+  return tmp.str();
+}