Update ATSPI code according to DALi coding rule
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-impl.cpp
index f76a9b4..11c580e 100644 (file)
 // 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-selection.h>
 #include <dali/internal/accessibility/bridge/bridge-text.h>
 #include <dali/internal/accessibility/bridge/bridge-value.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;
 
@@ -42,7 +50,8 @@ class BridgeImpl : public virtual BridgeBase,
                    public BridgeAction,
                    public BridgeValue,
                    public BridgeText,
-                   public BridgeEditableText
+                   public BridgeEditableText,
+                   public BridgeSelection
 {
   DBus::DBusClient                                              listenOnAtspiEnabledSignalClient;
   DBus::DBusClient                                              registryClient, directReadingClient;
@@ -90,18 +99,18 @@ public:
       return Consumed::NO;
     }
 
-    unsigned int evType = 0;
+    unsigned int keyType = 0;
 
     switch(type)
     {
       case KeyEventType::KEY_PRESSED:
       {
-        evType = 0;
+        keyType = 0;
         break;
       }
       case KeyEventType::KEY_RELEASED:
       {
-        evType = 1;
+        keyType = 1;
         break;
       }
       default:
@@ -110,7 +119,7 @@ public:
       }
     }
     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});
+    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});
     if(!result)
     {
       LOG() << result.getError().message;
@@ -151,6 +160,22 @@ public:
                                                                                         false);
   }
 
+  void StopReading(bool alsoNonDiscardable) override
+  {
+    if(!IsUp())
+    {
+      return;
+    }
+
+    directReadingClient.method<DBus::ValueOrError<void>(bool)>("StopReading").asyncCall([](DBus::ValueOrError<void> msg) {
+      if(!msg)
+      {
+        LOG() << "Direct reading command failed (" << msg.getError().message << ")";
+      }
+    },
+                                                                                        alsoNonDiscardable);
+  }
+
   void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
   {
     if(!IsUp())
@@ -174,14 +199,14 @@ public:
 
   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            = {};
     }
     highlightedActor     = {};
     highlightClearAction = {};
@@ -193,10 +218,10 @@ public:
 
   void Terminate() override
   {
-    if(data)
+    if(mData)
     {
-      data->currentlyHighlightedActor = {};
-      data->highlightActor            = {};
+      mData->mCurrentlyHighlightedActor = {};
+      mData->mHighlightActor            = {};
     }
     ForceDown();
     listenOnAtspiEnabledSignalClient = {};
@@ -219,6 +244,7 @@ public:
     BridgeValue::RegisterInterfaces();
     BridgeText::RegisterInterfaces();
     BridgeEditableText::RegisterInterfaces();
+    BridgeSelection::RegisterInterfaces();
 
     RegisterOnBridge(&application);
 
@@ -288,17 +314,19 @@ public:
 
   void Initialize() override
   {
-    auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
-    auto p   = req.property<bool>("ScreenReaderEnabled").get();
-    if(p)
+    auto dbusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
+    auto enabled = dbusClient.property<bool>("ScreenReaderEnabled").get();
+    if(enabled)
     {
-      screenReaderEnabled = std::get<0>(p);
+      screenReaderEnabled = std::get<0>(enabled);
     }
-    p = req.property<bool>("IsEnabled").get();
-    if(p)
+
+    enabled = dbusClient.property<bool>("IsEnabled").get();
+    if(enabled)
     {
-      isEnabled = std::get<0>(p);
+      isEnabled = std::get<0>(enabled);
     }
+
     if(screenReaderEnabled || isEnabled)
     {
       ForceUp();
@@ -310,14 +338,91 @@ public:
     return screenReaderEnabled;
   }
 
-  bool GetIsEnabled()
+  bool IsEnabled()
   {
     return isEnabled;
   }
 };
 
+static bool bridgeInitialized;
+
+static Bridge* CreateBridge()
+{
+  bridgeInitialized = 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();
+  }
+}
+
 Bridge* Bridge::GetCurrentBridge()
 {
-  static BridgeImpl* bridge = new BridgeImpl;
-  return bridge;
+  static Bridge* bridge;
+
+  if(bridge)
+  {
+    return bridge;
+  }
+  else if(autoInitState == 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(bridgeInitialized)
+  {
+    DALI_LOG_ERROR("Bridge::DisableAutoInit() called after bridge auto-initialization");
+  }
+
+  autoInitState = AutoInitState::DISABLED;
+}
+
+void Bridge::EnableAutoInit()
+{
+  autoInitState = AutoInitState::ENABLED;
+
+  if(bridgeInitialized)
+  {
+    return;
+  }
+
+  auto rootLayer       = Dali::Stage::GetCurrent().GetRootLayer();
+  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));
+  bridge->SetApplicationName(applicationName);
+  bridge->Initialize();
+
+  if(window && window.IsVisible())
+  {
+    bridge->ApplicationShown();
+  }
 }