// 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;
public BridgeAction,
public BridgeValue,
public BridgeText,
- public BridgeEditableText
+ public BridgeEditableText,
+ public BridgeSelection
{
DBus::DBusClient listenOnAtspiEnabledSignalClient;
DBus::DBusClient registryClient, directReadingClient;
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:
}
}
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;
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())
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 = {};
void Terminate() override
{
- if(data)
+ if(mData)
{
- data->currentlyHighlightedActor = {};
- data->highlightActor = {};
+ mData->mCurrentlyHighlightedActor = {};
+ mData->mHighlightActor = {};
}
ForceDown();
listenOnAtspiEnabledSignalClient = {};
BridgeValue::RegisterInterfaces();
BridgeText::RegisterInterfaces();
BridgeEditableText::RegisterInterfaces();
+ BridgeSelection::RegisterInterfaces();
RegisterOnBridge(&application);
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();
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();
+ }
}