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,
public BridgeSelection,
public BridgeApplication
{
- DBus::DBusClient accessibilityStatusClient;
- 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;
- Dali::CallbackBase* mIdleCallback = NULL;
+ 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()
{
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Emit()
+ */
Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) override
{
if(!IsUp())
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;
return std::get<0>(result) ? Consumed::YES : Consumed::NO;
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Pause()
+ */
void Pause() override
{
if(!IsUp())
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 << ")";
true);
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Resume()
+ */
void Resume() override
{
if(!IsUp())
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 << ")";
false);
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::StopReading()
+ */
void StopReading(bool alsoNonDiscardable) override
{
if(!IsUp())
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 << ")";
alsoNonDiscardable);
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Say()
+ */
void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) override
{
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) {
+ 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)
}
mData->mCurrentlyHighlightedActor = {};
mData->mHighlightActor = {};
+
+ mDisabledSignal.Emit();
}
- highlightedActor = {};
- highlightClearAction = {};
+ mHighlightedActor = {};
+ mHighlightClearAction = {};
BridgeAccessible::ForceDown();
- registryClient = {};
- directReadingClient = {};
- directReadingCallbacks.clear();
+ mRegistryClient = {};
+ mDirectReadingClient = {};
+ mDirectReadingCallbacks.clear();
+ mApplication.mChildren.clear();
+ mApplication.mWindows.clear();
+ }
+
+ void StopTimer()
+ {
+ if(mInitializeTimer)
+ {
+ mInitializeTimer.Stop();
+ }
+
+ if(mReadIsEnabledTimer)
+ {
+ mReadIsEnabledTimer.Stop();
+ }
+
+ if(mReadScreenReaderEnabledTimer)
+ {
+ mReadScreenReaderEnabledTimer.Stop();
+ }
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Terminate()
+ */
void Terminate() override
{
if(mData)
mData->mHighlightActor = {};
}
ForceDown();
+ StopTimer();
if((NULL != mIdleCallback) && Dali::Adaptor::IsAvailable())
{
Dali::Adaptor::Get().RemoveIdle(mIdleCallback);
}
- accessibilityStatusClient = {};
- dbusServer = {};
- con = {};
+ mAccessibilityStatusClient = {};
+ mDbusServer = {};
+ mConnectionPtr = {};
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::ForceUp()
+ */
ForceUpResult ForceUp() override
{
if(BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP)
BridgeSelection::RegisterInterfaces();
BridgeApplication::RegisterInterfaces();
- RegisterOnBridge(&application);
+ RegisterOnBridge(&mApplication);
+
+ 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) {
- auto it = directReadingCallbacks.find(id);
- if(it != directReadingCallbacks.end())
+ 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)
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();
+ auto rootLayer = Dali::Stage::GetCurrent().GetRootLayer();
+ auto window = Dali::DevelWindow::Get(rootLayer);
+ EmitActivate(window); // Currently, sends a signal that the default window is activated here.
}
+
+ mEnabledSignal.Emit();
+
return ForceUpResult::JUST_STARTED;
}
- void EmitActivate()
+ /**
+ * @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 win = application.getActiveWindow();
- if(win)
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
{
- win->Emit(WindowEvent::ACTIVATE, 0);
+ windowAccessible->EmitShowing(true);
}
}
- void EmitDeactivate()
+ /**
+ * @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::DEACTIVATE, 0);
+ windowAccessible->EmitShowing(false);
}
}
- void WindowHidden() override
+ /**
+ * @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)
{
- if(isShown && IsUp())
+ auto windowAccessible = mApplication.GetWindowAccessible(window);
+ if(windowAccessible)
{
- EmitDeactivate();
+ windowAccessible->Emit(WindowEvent::ACTIVATE, 0);
}
- isShown = false;
}
- void WindowShown() 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)
{
- EmitActivate();
+ windowAccessible->Emit(WindowEvent::DEACTIVATE, 0);
}
- isShown = true;
}
- void ReadAndListenProperty()
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowShown()
+ */
+ void WindowShown(Dali::Window window) override
{
- // read property
- auto enabled = accessibilityStatusClient.property<bool>("ScreenReaderEnabled").get();
- if(enabled)
+ if(!mIsShown && IsUp())
{
- screenReaderEnabled = std::get<0>(enabled);
+ EmitShown(window);
}
- enabled = accessibilityStatusClient.property<bool>("IsEnabled").get();
- if(enabled)
+ mIsShown = true;
+ }
+
+ /**
+ * @copydoc Dali::Accessibility::Bridge::WindowHidden()
+ */
+ void WindowHidden(Dali::Window window) override
+ {
+ if(mIsShown && IsUp())
{
- isEnabled = std::get<0>(enabled);
+ EmitHidden(window);
}
- if(screenReaderEnabled || isEnabled)
+ 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())
{
- ForceUp();
+ EmitDeactivate(window);
}
+ }
+
+ bool ReadIsEnabledTimerCallback()
+ {
+ ReadIsEnabledProperty();
+ return false;
+ }
- // listen property change
- accessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
- screenReaderEnabled = res;
- if(screenReaderEnabled || isEnabled)
+ 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(mIsEnabled)
+ {
+ ForceUp();
+ }
+ });
+ }
+
+ void ListenIsEnabledProperty()
+ {
+ mAccessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
+ mIsEnabled = res;
+ if(mIsScreenReaderEnabled || mIsEnabled)
{
ForceUp();
}
ForceDown();
}
});
+ }
+
+ bool ReadScreenReaderEnabledTimerCallback()
+ {
+ ReadScreenReaderEnabledProperty();
+ return false;
+ }
+
+ void ReadScreenReaderEnabledProperty()
+ {
+ 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(mIsScreenReaderEnabled)
+ {
+ ForceUp();
+ }
+ });
+ }
- accessibilityStatusClient.addPropertyChangedEvent<bool>("IsEnabled", [this](bool res) {
- isEnabled = res;
- if(screenReaderEnabled || isEnabled)
+ void ListenScreenReaderEnabledProperty()
+ {
+ mAccessibilityStatusClient.addPropertyChangedEvent<bool>("ScreenReaderEnabled", [this](bool res) {
+ mIsScreenReaderEnabled = res;
+ if(mIsScreenReaderEnabled || mIsEnabled)
{
ForceUp();
}
});
}
+ void ReadAndListenProperties()
+ {
+ ReadIsEnabledProperty();
+ ListenIsEnabledProperty();
+
+ ReadScreenReaderEnabledProperty();
+ ListenScreenReaderEnabledProperty();
+ }
+
bool InitializeAccessibilityStatusClient()
{
- accessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
+ mAccessibilityStatusClient = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
- if (!accessibilityStatusClient)
+ 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() )
{
- 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;
}
+ /**
+ * @copydoc Dali::Accessibility::Bridge::Initialize()
+ */
void Initialize() override
{
if ( InitializeAccessibilityStatusClient() )
{
- ReadAndListenProperty();
+ ReadAndListenProperties();
return;
}
}
}
- bool GetScreenReaderEnabled()
+ /**
+ * @copydoc Dali::Accessibility::Bridge::GetScreenReaderEnabled()
+ */
+ bool GetScreenReaderEnabled() override
{
- return screenReaderEnabled;
+ return mIsScreenReaderEnabled;
}
- bool IsEnabled()
+ /**
+ * @copydoc Dali::Accessibility::Bridge::IsEnabled()
+ */
+ bool IsEnabled() override
{
- return isEnabled;
+ return mIsEnabled;
}
-};
+}; // BridgeImpl
+
+namespace // unnamed namespace
+{
-static bool bridgeInitialized;
+bool INITIALIZED_BRIDGE = false;
-static Bridge* CreateBridge()
+/**
+ * @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()
{
- bridgeInitialized = true;
+ INITIALIZED_BRIDGE = true;
try
{
}
}
+} // unnamed namespace
+
+// Dali::Accessibility::Bridge class implementation
+
Bridge* Bridge::GetCurrentBridge()
{
static Bridge* bridge;
{
return bridge;
}
- else if(autoInitState == AutoInitState::ENABLED)
+ else if(mAutoInitState == AutoInitState::ENABLED)
{
bridge = CreateBridge();
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;
}
- 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 accessible = Accessibility::Accessible::Get(rootLayer, true);
+
auto* bridge = Bridge::GetCurrentBridge();
- bridge->AddTopLevelWindow(Dali::Accessibility::Accessible::Get(rootLayer, true));
+ bridge->AddTopLevelWindow(accessible);
bridge->SetApplicationName(applicationName);
bridge->Initialize();
if(window && window.IsVisible())
{
- bridge->WindowShown();
+ bridge->WindowShown(window);
}
}