[AT-SPI] Add Bridge::{Enabled,Disabled}Signal()
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
index aaed7fb..181b440 100644 (file)
@@ -43,6 +43,9 @@
 
 using namespace Dali::Accessibility;
 
+/**
+ * @brief The BridgeImpl class is to implement some Bridge functions.
+ */
 class BridgeImpl : public virtual BridgeBase,
                    public BridgeAccessible,
                    public BridgeObject,
@@ -55,45 +58,25 @@ class BridgeImpl : public virtual BridgeBase,
                    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;
 
 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();
-      }
-    });
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Emit()
+   */
   Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
   {
     if(!IsUp())
@@ -120,8 +103,9 @@ 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>{keyType, 0, static_cast<int32_t>(keyCode), 0, static_cast<int32_t>(timeStamp), keyName, isText ? 1 : 0});
+
+    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;
@@ -130,6 +114,9 @@ public:
     return std::get<0>(result) ? Consumed::YES : Consumed::NO;
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Pause()
+   */
   void Pause() override
   {
     if(!IsUp())
@@ -137,7 +124,7 @@ public:
       return;
     }
 
-    directReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
@@ -146,6 +133,9 @@ public:
                                                                                         true);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Resume()
+   */
   void Resume() override
   {
     if(!IsUp())
@@ -153,7 +143,7 @@ public:
       return;
     }
 
-    directReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("PauseResume").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
@@ -162,6 +152,9 @@ public:
                                                                                         false);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::StopReading()
+   */
   void StopReading(bool alsoNonDiscardable) override
   {
     if(!IsUp())
@@ -169,7 +162,7 @@ public:
       return;
     }
 
-    directReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
+    mDirectReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
       if(!msg)
       {
         LOG() << "Direct reading command failed (" << msg.getError().message << ")";
@@ -178,6 +171,9 @@ public:
                                                                                         alsoNonDiscardable);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Say()
+   */
   void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
   {
     if(!IsUp())
@@ -185,20 +181,23 @@ public:
       return;
     }
 
-    directReadingClient.method<DBus::ValueOrError<std::string, bool, int32_t>(std::string, bool)>("ReadCommand").asyncCall([=](DBus::ValueOrError<std::string, bool, int32_t> msg) {
+    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)
       {
-        directReadingCallbacks.emplace(std::get<2>(msg), callback);
+        mDirectReadingCallbacks.emplace(std::get<2>(msg), callback);
       }
     },
                                                                                                                            text,
                                                                                                                            discardable);
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::ForceDown()
+   */
   void ForceDown() override
   {
     if(mData)
@@ -209,15 +208,20 @@ public:
       }
       mData->mCurrentlyHighlightedActor = {};
       mData->mHighlightActor            = {};
+
+      mDisabledSignal.Emit();
     }
-    highlightedActor     = {};
-    highlightClearAction = {};
+    mHighlightedActor     = {};
+    mHighlightClearAction = {};
     BridgeAccessible::ForceDown();
-    registryClient      = {};
-    directReadingClient = {};
-    directReadingCallbacks.clear();
+    mRegistryClient       = {};
+    mDirectReadingClient  = {};
+    mDirectReadingCallbacks.clear();
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Terminate()
+   */
   void Terminate() override
   {
     if(mData)
@@ -226,11 +230,18 @@ public:
       mData->mHighlightActor            = {};
     }
     ForceDown();
-    listenOnAtspiEnabledSignalClient = {};
-    dbusServer                       = {};
-    con                              = {};
+    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)
@@ -249,21 +260,24 @@ public:
     BridgeSelection::RegisterInterfaces();
     BridgeApplication::RegisterInterfaces();
 
-    RegisterOnBridge(&application);
+    RegisterOnBridge(&mApplication);
 
-    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) {
-      auto it = directReadingCallbacks.find(id);
-      if(it != directReadingCallbacks.end())
+    mRegistryClient      = {AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, mConnectionPtr};
+    mDirectReadingClient = DBus::DBusClient{DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, mConnectionPtr};
+
+    mDirectReadingClient.addSignal<void(int32_t, std::string)>("ReadingStateChanged", [=](int32_t id, std::string readingState) {
+      auto it = mDirectReadingCallbacks.find(id);
+      if(it != mDirectReadingCallbacks.end())
       {
         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)
@@ -271,87 +285,197 @@ public:
       LOG() << "Call to Embed failed: " << res.getError().message;
     }
     assert(res);
-    application.parent.SetAddress(std::move(std::get<0>(res)));
-    if(isShown)
+
+    mApplication.mParent.SetAddress(std::move(std::get<0>(res)));
+    if(mIsShown)
     {
       EmitActivate();
     }
+
+    mEnabledSignal.Emit();
+
     return ForceUpResult::JUST_STARTED;
   }
 
+  /**
+   * @brief Sends a signal to dbus that the default window is activated.
+   *
+   * TODO : This is subject to change if/when we implement multi-window support.
+   * @see BridgeObject::Emit()
+   */
   void EmitActivate()
   {
-    auto win = application.getActiveWindow();
+    auto win = mApplication.GetActiveWindow();
     if(win)
     {
       win->Emit(WindowEvent::ACTIVATE, 0);
     }
   }
 
+  /**
+   * @brief Sends a signal to dbus that the default window is deactivated.
+   *
+   * TODO : This is subject to change if/when we implement multi-window support.
+   * @see BridgeObject::Emit()
+   */
   void EmitDeactivate()
   {
-    auto win = application.getActiveWindow();
+    auto win = mApplication.GetActiveWindow();
     if(win)
     {
       win->Emit(WindowEvent::DEACTIVATE, 0);
     }
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowHidden()
+   */
   void WindowHidden() override
   {
-    if(isShown && IsUp())
+    if(mIsShown && IsUp())
     {
       EmitDeactivate();
     }
-    isShown = false;
+    mIsShown = false;
   }
 
+  /**
+   * @copydoc Dali::Accessibility::Bridge::WindowShown()
+   */
   void WindowShown() override
   {
-    if(!isShown && IsUp())
+    if(!mIsShown && IsUp())
     {
       EmitActivate();
     }
-    isShown = true;
+    mIsShown = true;
   }
 
-  void Initialize() override
+  void ReadAndListenProperty()
   {
-    auto dbusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
-    auto enabled = dbusClient.property<bool>("ScreenReaderEnabled").get();
+    // read property
+    auto enabled = mAccessibilityStatusClient.property<bool>("ScreenReaderEnabled").get();
     if(enabled)
     {
-      screenReaderEnabled = std::get<0>(enabled);
+      mIsScreenReaderEnabled = std::get<0>(enabled);
     }
 
-    enabled = dbusClient.property<bool>("IsEnabled").get();
+    enabled = mAccessibilityStatusClient.property<bool>("IsEnabled").get();
     if(enabled)
     {
-      isEnabled = std::get<0>(enabled);
+      mIsEnabled = std::get<0>(enabled);
     }
 
-    if(screenReaderEnabled || isEnabled)
+    if(mIsScreenReaderEnabled || mIsEnabled)
     {
       ForceUp();
     }
+
+    // listen property change
+    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
+      mIsScreenReaderEnabled = res;
+      if(mIsScreenReaderEnabled || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+
+    mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
+      mIsEnabled = res;
+      if(mIsScreenReaderEnabled || mIsEnabled)
+      {
+        ForceUp();
+      }
+      else
+      {
+        ForceDown();
+      }
+    });
+  }
+
+  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 OnIdleSignal()
+  {
+    if ( InitializeAccessibilityStatusClient() )
+    {
+      ReadAndListenProperty();
+      mIdleCallback = NULL;
+      return false;
+    }
+
+    return true;
   }
 
-  bool GetScreenReaderEnabled()
+  /**
+   * @copydoc Dali::Accessibility::Bridge::Initialize()
+   */
+  void Initialize() override
   {
-    return screenReaderEnabled;
+    if ( InitializeAccessibilityStatusClient() )
+    {
+      ReadAndListenProperty();
+      return;
+    }
+
+    // Initialize failed. Try it again on Idle
+    if( Dali::Adaptor::IsAvailable() )
+    {
+      Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+      if( NULL == mIdleCallback )
+      {
+        mIdleCallback = MakeCallback( this, &BridgeImpl::OnIdleSignal );
+        adaptor.AddIdle( mIdleCallback, true );
+      }
+    }
   }
 
-  bool IsEnabled()
+  /**
+   * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
+   */
+  bool GetScreenReaderEnabled() override
   {
-    return isEnabled;
+    return mIsScreenReaderEnabled;
   }
-};
 
-static bool bridgeInitialized;
+  /**
+   * @copydoc Dali::Accessibility::Bridge::IsEnabled()
+   */
+  bool IsEnabled() override
+  {
+    return mIsEnabled;
+  }
+}; // BridgeImpl
 
-static Bridge* CreateBridge()
+namespace // unnamed namespace
 {
-  bridgeInitialized = true;
+
+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
   {
@@ -371,6 +495,10 @@ static Bridge* CreateBridge()
   }
 }
 
+} // unnamed namespace
+
+// Dali::Accessibility::Bridge class implementation
+
 Bridge* Bridge::GetCurrentBridge()
 {
   static Bridge* bridge;
@@ -379,7 +507,7 @@ Bridge* Bridge::GetCurrentBridge()
   {
     return bridge;
   }
-  else if(autoInitState == AutoInitState::ENABLED)
+  else if(mAutoInitState == AutoInitState::ENABLED)
   {
     bridge = CreateBridge();
 
@@ -398,19 +526,19 @@ Bridge* Bridge::GetCurrentBridge()
 
 void Bridge::DisableAutoInit()
 {
-  if(bridgeInitialized)
+  if(INITIALIZED_BRIDGE)
   {
     DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
   }
 
-  autoInitState = AutoInitState::DISABLED;
+  mAutoInitState = AutoInitState::DISABLED;
 }
 
 void Bridge::EnableAutoInit()
 {
-  autoInitState = AutoInitState::ENABLED;
+  mAutoInitState = AutoInitState::ENABLED;
 
-  if(bridgeInitialized)
+  if(INITIALIZED_BRIDGE)
   {
     return;
   }