X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Faccessibility%2Fbridge%2Fbridge-impl.cpp;h=f76a0eae3bb57a260a9dfa8574fc54d7a9a35588;hb=1646a271a6cd0854eec41c68e37b39478b83fb96;hp=817b445cf377b7d18380469d192dd2d2bc2ec136;hpb=80e4cfd5255b3a378e1afe854190ff970ec594c0;p=platform%2Fcore%2Fuifw%2Fdali-adaptor.git diff --git a/dali/internal/accessibility/bridge/bridge-impl.cpp b/dali/internal/accessibility/bridge/bridge-impl.cpp index 817b445..f76a0ea 100644 --- a/dali/internal/accessibility/bridge/bridge-impl.cpp +++ b/dali/internal/accessibility/bridge/bridge-impl.cpp @@ -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. @@ -27,20 +27,23 @@ // INTERNAL INCLUDES #include #include +#include #include #include +#include #include #include #include -#include #include +#include #include #include #include +#include +#include #include #include -#include -#include +#include #include #include @@ -48,7 +51,6 @@ using namespace Dali::Accessibility; namespace // unnamed namespace { - const int RETRY_INTERVAL = 1000; } // unnamed namespace @@ -69,27 +71,27 @@ class BridgeImpl : public virtual BridgeBase, public BridgeApplication, public BridgeHypertext, public BridgeHyperlink, - public BridgeSocket + 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> mDirectReadingCallbacks; + DBus::DBusClient mAccessibilityStatusClient{}; + DBus::DBusClient mRegistryClient{}; + DBus::DBusClient mDirectReadingClient{}; + bool mIsScreenReaderEnabled{false}; + bool mIsEnabled{false}; + std::unordered_map> mDirectReadingCallbacks{}; Dali::Actor mHighlightedActor; - std::function mHighlightClearAction; - Dali::CallbackBase* mIdleCallback = NULL; + std::function 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() @@ -147,7 +149,7 @@ public: LOG() << "Direct reading command failed (" << msg.getError().message << ")\n"; } }, - true); + true); } /** @@ -166,7 +168,7 @@ public: LOG() << "Direct reading command failed (" << msg.getError().message << ")\n"; } }, - false); + false); } /** @@ -185,7 +187,7 @@ public: LOG() << "Direct reading command failed (" << msg.getError().message << ")\n"; } }, - alsoNonDiscardable); + alsoNonDiscardable); } /** @@ -208,8 +210,8 @@ public: mDirectReadingCallbacks.emplace(std::get<2>(msg), callback); } }, - text, - discardable); + text, + discardable); } /** @@ -227,15 +229,17 @@ public: mData->mHighlightActor = {}; mDisabledSignal.Emit(); + UnembedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"}); + ReleaseBusName(mPreferredBusName); } + mHighlightedActor = {}; mHighlightClearAction = {}; BridgeAccessible::ForceDown(); - mRegistryClient = {}; - mDirectReadingClient = {}; + mRegistryClient = {}; + mDirectReadingClient = {}; mDirectReadingCallbacks.clear(); mApplication.mChildren.clear(); - mApplication.mWindows.clear(); ClearTimer(); } @@ -273,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 = {}; } @@ -281,9 +290,9 @@ public: { Dali::Adaptor::Get().RemoveIdle(mIdleCallback); } - mAccessibilityStatusClient = {}; - mDbusServer = {}; - mConnectionPtr = {}; + mAccessibilityStatusClient = {}; + mDbusServer = {}; + mConnectionPtr = {}; } bool ForceUpTimerCallback() @@ -329,6 +338,8 @@ public: BridgeHypertext::RegisterInterfaces(); BridgeHyperlink::RegisterInterfaces(); BridgeSocket::RegisterInterfaces(); + BridgeTable::RegisterInterfaces(); + BridgeTableCell::RegisterInterfaces(); RegisterOnBridge(&mApplication); @@ -347,26 +358,12 @@ public: } }); - auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, Accessible::GetInterfaceName(AtspiInterface::SOCKET), mConnectionPtr}; - Address root{"", "root"}; - auto res = proxy.method("Embed").call(root); - if(!res) - { - LOG() << "Call to Embed failed: " << res.getError().message; - } - assert(res); - - mApplication.mParent.SetAddress(std::move(std::get<0>(res))); + RequestBusName(mPreferredBusName); + auto parentAddress = EmbedSocket(mApplication.GetAddress(), {AtspiDbusNameRegistry, "root"}); + mApplication.mParent.SetAddress(std::move(parentAddress)); mEnabledSignal.Emit(); - if(mIsShown) - { - 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. - } - return ForceUpResult::JUST_STARTED; } @@ -431,15 +428,60 @@ public: } /** + * @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(detail)); + } + } + + /** + * @brief Sends a signal to dbus that the window is maximized. + * + * @param[in] window The window to be maximized + * @see BridgeObject::Emit() + */ + void EmitMaximize(Dali::Window window) + { + auto windowAccessible = mApplication.GetWindowAccessible(window); + if(windowAccessible) + { + windowAccessible->Emit(WindowEvent::MAXIMIZE, 0); + } + } + + /** * @copydoc Dali::Accessibility::Bridge::WindowShown() */ void WindowShown(Dali::Window window) override { - if(!mIsShown && IsUp()) + if(IsUp()) { EmitShown(window); } - mIsShown = true; } /** @@ -447,11 +489,10 @@ public: */ void WindowHidden(Dali::Window window) override { - if(mIsShown && IsUp()) + if(IsUp()) { EmitHidden(window); } - mIsShown = false; } /** @@ -459,7 +500,7 @@ public: */ void WindowFocused(Dali::Window window) override { - if(mIsShown && IsUp()) + if(IsUp()) { EmitActivate(window); } @@ -470,13 +511,46 @@ public: */ void WindowUnfocused(Dali::Window window) override { - if(mIsShown && IsUp()) + 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 @@ -553,7 +627,7 @@ public: void ReadScreenReaderEnabledProperty() { // can be true because of SuppressScreenReader before init - if (!mAccessibilityStatusClient) + if(!mAccessibilityStatusClient) { return; } @@ -587,7 +661,7 @@ public: void EmitScreenReaderEnabledSignal() { - if (mIsScreenReaderEnabled) + if(mIsScreenReaderEnabled) { mScreenReaderEnabledSignal.Emit(); } @@ -619,7 +693,7 @@ public: { 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; @@ -630,7 +704,7 @@ public: bool InitializeTimerCallback() { - if ( InitializeAccessibilityStatusClient() ) + if(InitializeAccessibilityStatusClient()) { ReadAndListenProperties(); return false; @@ -640,7 +714,7 @@ public: bool OnIdleSignal() { - if ( InitializeAccessibilityStatusClient() ) + if(InitializeAccessibilityStatusClient()) { ReadAndListenProperties(); mIdleCallback = NULL; @@ -663,20 +737,20 @@ public: */ void Initialize() override { - if ( InitializeAccessibilityStatusClient() ) + if(InitializeAccessibilityStatusClient()) { 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); } } } @@ -696,11 +770,99 @@ public: { return mIsEnabled; } + + Address EmbedSocket(const Address& plug, const Address& socket) override + { + auto client = CreateSocketClient(socket); + auto reply = client.method("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("Embedded").asyncCall([](DBus::ValueOrError) {}, ATSPI_PREFIX_PATH + plug.GetPath()); + } + + void UnembedSocket(const Address& plug, const Address& socket) override + { + auto client = CreateSocketClient(socket); + + client.method("Unembed").asyncCall([](DBus::ValueOrError) {}, 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("SetOffset").asyncCall([](DBus::ValueOrError) {}, 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; /** @@ -783,7 +945,7 @@ void Bridge::EnableAutoInit() auto window = Dali::DevelWindow::Get(rootLayer); auto applicationName = Dali::Internal::Adaptor::Adaptor::GetApplicationPackageName(); - auto accessible = Accessibility::Accessible::Get(rootLayer, true); + auto accessible = Accessibility::Accessible::Get(rootLayer); auto bridge = Bridge::GetCurrentBridge(); bridge->AddTopLevelWindow(accessible); @@ -795,3 +957,23 @@ void Bridge::EnableAutoInit() 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(); +}