1 #ifndef DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
2 #define DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
5 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/math/rect.h>
28 #include <unordered_set>
31 #include <dali/devel-api/adaptor-framework/accessibility.h>
32 #include <dali/public-api/adaptor-framework/window.h>
36 namespace Accessibility
39 class ProxyAccessible;
42 * @brief Base class for different accessibility bridges.
44 * Bridge is resposible for initializing and managing connection on accessibility bus.
45 * Accessibility clients will not get any information about UI without initialized and upraised bridge.
46 * Concrete implementation depends on the accessibility technology available on the platform.
48 * @note This class is singleton.
50 struct DALI_ADAPTOR_API Bridge
52 enum class ForceUpResult
62 virtual ~Bridge() = default;
65 * @brief Gets bus name which bridge is initialized on.
67 * @return The bus name
69 virtual const std::string& GetBusName() const = 0;
72 * @brief Registers top level window.
74 * Hierarchy of objects visible for accessibility clients is based on tree-like
75 * structure created from Actors objects. This method allows to connect chosen
76 * object as direct ancestor of application and therefore make it visible for
77 * accessibility clients.
79 * @param[in] object The accessible object
81 virtual void AddTopLevelWindow(Accessible* object) = 0;
84 * @brief Removes top level window.
86 * Hierarchy of objects visible for accessibility clients is based on tree-like
87 * structure created from Actors objects. This method removes previously added
88 * window from visible accessibility objects.
90 * @param[in] object The accessible object
92 virtual void RemoveTopLevelWindow(Accessible* object) = 0;
95 * @brief Adds object on the top of the stack of "default label" sourcing objects.
97 * @see GetDefaultLabel
99 * @param[in] object The accessible object
101 virtual void RegisterDefaultLabel(Accessible* object) = 0;
104 * @brief Removes object from the stack of "default label" sourcing objects.
106 * @see GetDefaultLabel
108 * @param[in] object The accessible object
110 virtual void UnregisterDefaultLabel(Accessible* object) = 0;
113 * @brief Gets the top-most object from the stack of "default label" sourcing objects.
115 * The "default label" is a reading material (text) derived from an accesibility object
116 * that could be read by screen-reader immediately after the navigation context has changed
117 * (window activates, popup shows up, tab changes) and before first UI element is highlighted.
119 * @param[in] root The root of the navigation context for which to retrieve the default label.
121 * @return The handler to accessibility object
122 * @note This is a Tizen only feature not present in upstream ATSPI.
123 * Feature can be enabled/disabled for particular context root object
124 * by setting value of its accessibility attribute "default_label".
125 * Following strings are valid values for "default_label" attribute: "enabled", "disabled".
126 * Any other value will be interpreted as "enabled".
128 virtual Accessible* GetDefaultLabel(Accessible* root) const = 0;
131 * @brief Sets name of current application which will be visible on accessibility bus.
133 * @param[in] name The application name
135 virtual void SetApplicationName(std::string name) = 0;
138 * @brief Sets the name of the GUI toolkit that AT-SPI clients can query.
140 * The default name is "dali".
142 * @param toolkitName The toolkit name
144 virtual void SetToolkitName(std::string_view toolkitName) = 0;
147 * @brief Gets object being root of accessibility tree.
149 * @return handler to accessibility object
151 virtual Accessible* GetApplication() const = 0;
154 * @brief Finds an object in accessibility tree.
156 * @param[in] path The path to object
158 * @return The handler to accessibility object
160 virtual Accessible* FindByPath(const std::string& path) const = 0;
163 * @brief Notifies accessibility dbus that window has just been created.
165 * @param[in] window The window to be created
167 virtual void WindowCreated(Window window) = 0;
170 * @brief Notifies accessibility dbus that window has just been shown.
172 * @param[in] window The window to be shown
174 virtual void WindowShown(Window window) = 0;
177 * @brief Notifies accessibility dbus that window has just been hidden.
179 * @param[in] window The window to be hidden
181 virtual void WindowHidden(Window window) = 0;
184 * @brief Notifies accessibility dbus that window has just been focused.
186 * @param[in] window The window to be focused
188 virtual void WindowFocused(Window window) = 0;
191 * @brief Notifies accessibility dbus that window has just been out of focus.
193 * @param[in] window The window to be out of focus
195 virtual void WindowUnfocused(Window window) = 0;
198 * @brief Notifies accessibility dbus that window has just been minimized.
200 * @param[in] window The window to be minimized
202 virtual void WindowMinimized(Window window) = 0;
205 * @brief Notifies accessibility dbus that window has just been restored.
207 * @param[in] window The window to be restored
208 * @param[in] detail Restored window state
210 virtual void WindowRestored(Window window, WindowRestoreType detail) = 0;
213 * @brief Notifies accessibility dbus that window has just been maximized.
215 * @param[in] window The window to be maximized
217 virtual void WindowMaximized(Window window) = 0;
220 * @brief Initializes accessibility bus.
222 virtual void Initialize() = 0;
225 * @brief Terminates accessibility bus.
227 virtual void Terminate() = 0;
230 * @brief This method is called, when bridge is being activated.
232 virtual ForceUpResult ForceUp()
236 return ForceUpResult::ALREADY_UP;
238 mData = std::make_shared<Data>();
239 mData->mBridge = this;
240 return ForceUpResult::JUST_STARTED;
244 * @brief This method is called, when bridge is being deactivated.
246 virtual void ForceDown() = 0;
249 * @brief Checks if bridge is activated or not.
250 * @return True if brige is activated.
258 * @brief Emits cursor-moved event on at-spi bus.
260 * @param[in] obj The accessible object
261 * @param[in] cursorPosition The new cursor position
263 virtual void EmitCursorMoved(Accessible* obj, unsigned int cursorPosition) = 0;
266 * @brief Emits active-descendant-changed event on at-spi bus.
268 * @param[in] obj The accessible object
269 * @param[in] child The child of the object
271 virtual void EmitActiveDescendantChanged(Accessible* obj, Accessible* child) = 0;
274 * @brief Emits text-changed event on at-spi bus.
276 * @param[in] obj The accessible object
277 * @param[in] state The changed state for text, such as Inserted or Deleted
278 * @param[in] position The cursor position
279 * @param[in] length The text length
280 * @param[in] content The changed text
282 virtual void EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content) = 0;
285 * @brief Emits MoveOuted event on at-spi bus.
287 * @param[in] obj Accessible object
288 * @param[in] type Direction type when an Accessible object moves out of screen
290 virtual void EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type) = 0;
293 * @brief Emits "org.a11y.atspi.Socket.Available" event on AT-SPI bus.
295 * @param obj Accessible object
297 virtual void EmitSocketAvailable(Accessible* obj) = 0;
300 * @brief Emits ScrollStarted event on at-spi bus.
302 * @param obj Accessible Object
304 virtual void EmitScrollStarted(Accessible *obj) = 0;
307 * @brief Emits ScrollFinished event on at-spi bus.
309 * @param obj Accessible Object
311 virtual void EmitScrollFinished(Accessible *obj) = 0;
314 * @brief Emits state-changed event on at-spi bus.
316 * @param[in] obj The accessible object
317 * @param[in] state The accessibility state (SHOWING, HIGHLIGHTED, etc)
318 * @param[in] newValue Whether the state value is changed to new value or not.
319 * @param[in] reserved Reserved. (Currently, this argument is not implemented in dali)
321 virtual void EmitStateChanged(Accessible* obj, State state, int newValue, int reserved = 0) = 0;
324 * @brief Emits window event on at-spi bus.
326 * @param[in] obj The accessible object
327 * @param[in] event The enumerated window event
328 * @param[in] detail The additional parameter which interpretation depends on chosen event
330 virtual void Emit(Accessible* obj, WindowEvent event, unsigned int detail = 0) = 0;
333 * @brief Emits property-changed event on at-spi bus.
335 * @param[in] obj The accessible object
336 * @param[in] event Property changed event
338 virtual void Emit(Accessible* obj, ObjectPropertyChangeEvent event) = 0;
341 * @brief Emits bounds-changed event on at-spi bus.
343 * @param[in] obj The accessible object
344 * @param[in] rect The rectangle for changed bounds
346 virtual void EmitBoundsChanged(Accessible* obj, Rect<> rect) = 0;
349 * @brief Emits org.a11y.atspi.Event.Window.PostRender on the AT-SPI bus.
351 * @param[in] obj The Accessible sender object
353 * The sender of this event is expected to be an Accessible object that
354 * represents a top-level window.
356 * The actual number of events emitted during a given time interval may be smaller
357 * than the number of calls to this method, but at least one is guaranteed.
359 virtual void EmitPostRender(Accessible *obj) = 0;
362 * @brief Emits key event on at-spi bus.
364 * Screen-reader might receive this event and reply, that given keycode is consumed. In that case
365 * further processing of the keycode should be ignored.
367 * @param[in] type Key event type
368 * @param[in] keyCode Key code
369 * @param[in] keyName Key name
370 * @param[in] timeStamp Time stamp
371 * @param[in] isText Whether it's text or not
372 * @return Whether this event is consumed or not
374 virtual Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) = 0;
377 * @brief Reads given text by screen reader
379 * @param[in] text The text to read
380 * @param[in] discardable If TRUE, reading can be discarded by subsequent reading requests,
381 * if FALSE the reading must finish before next reading request can be started
382 * @param[in] callback the callback function that is called on reading signals emitted
383 * during processing of this reading request.
384 * Callback can be one of the following signals:
385 * ReadingCancelled, ReadingStopped, ReadingSkipped
387 virtual void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) = 0;
390 * @brief Force accessibility client to pause.
392 virtual void Pause() = 0;
395 * @brief Force accessibility client to resume.
397 virtual void Resume() = 0;
400 * @brief Cancels anything screen-reader is reading / has queued to read
402 * @param[in] alsoNonDiscardable whether to cancel non-discardable readings as well
404 virtual void StopReading(bool alsoNonDiscardable) = 0;
407 * @brief Suppresses reading of screen-reader
409 * @param[in] suppress whether to suppress reading of screen-reader
411 virtual void SuppressScreenReader(bool suppress) = 0;
414 * @brief Gets screen reader status.
416 * @return True if screen reader is enabled
418 virtual bool GetScreenReaderEnabled() = 0;
421 * @brief Gets ATSPI status.
423 * @return True if ATSPI is enabled
425 virtual bool IsEnabled() = 0;
428 * @brief Calls socket.Embed(plug) via D-Bus.
430 * @param[in] plug The plug
431 * @param[in] socket The socket
433 * @return Address returned by the D-Bus call.
435 * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
436 * @see UnembedSocket()
438 virtual Address EmbedSocket(const Address& plug, const Address& socket) = 0;
441 * @brief Calls socket.Embedded(plug) via D-Bus.
443 * The "Embedded" D-Bus method is an ATK extension.
444 * See 'impl_Embedded' in AT_SPI2_ATK/atk-adaptor/adaptors/socket-adaptor.c for more information.
446 * @param[in] plug The plug
447 * @param[in] socket The socket
449 virtual void EmbedAtkSocket(const Address& plug, const Address& socket) = 0;
452 * @brief Calls socket.Unmbed(plug) via D-Bus.
454 * @param[in] plug The plug
455 * @param[in] socket The socket
457 * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
460 virtual void UnembedSocket(const Address& plug, const Address& socket) = 0;
463 * @brief Calls socket.SetOffset(x, y) via D-Bus.
465 * The "SetOffset" D-Bus method is a DALi extension. It can be used to inform a DALi widget about
466 * its position on the screen.
468 * @param[in] socket The socket
469 * @param[in] x Horizontal offset
470 * @param[in] y Vertical offset
472 * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
474 * @see SetExtentsOffset()
476 virtual void SetSocketOffset(ProxyAccessible* socket, std::int32_t x, std::int32_t y) = 0;
479 * @brief Sets the global extents offset.
481 * This offset will be added during serialization of GetExtents() return value to D-Bus.
482 * Local calls to GetExtents() are unaffected.
484 * @param[in] x Horizontal offset
485 * @param[in] y Vertical offset
487 * @see SetSocketOffset()
488 * @see Dali::Accessibility::Component::GetExtents()
490 virtual void SetExtentsOffset(std::int32_t x, std::int32_t y) = 0;
493 * @brief Sets the preferred bus name.
495 * If the Bridge is enabled, it will immediately release the previous name and request the new one.
497 * Otherwise, the Bridge will request this name on AT-SPI activation (and release it on deactivation).
498 * It is up to the caller to determine whether a given name will be available in the system.
500 * @param preferredBusName The preferred bus name
502 virtual void SetPreferredBusName(std::string_view preferredBusName) = 0;
505 * @brief Returns instance of bridge singleton object.
507 * @return The current bridge object
509 static std::shared_ptr<Bridge> GetCurrentBridge();
512 * @brief Blocks auto-initialization of AT-SPI bridge
514 * Use this only if your application starts before DBus does, and call it early in main()
515 * (before GetCurrentBridge() is called by anyone). GetCurrentBridge() will then return an
516 * instance of DummyBridge.
518 * When DBus is ready, call EnableAutoInit(). Please note that GetCurrentBridge() may still
519 * return an instance of DummyBridge if AT-SPI was disabled at compile time or using an
520 * environment variable, or if creating the real bridge failed.
522 * @see Dali::Accessibility::DummyBridge
523 * @see Dali::Accessibility::Bridge::EnableAutoInit
525 static void DisableAutoInit();
528 * @brief Re-enables auto-initialization of AT-SPI bridge
530 * Normal applications do not have to call this function. GetCurrentBridge() tries to
531 * initialize the AT-SPI bridge when it is called for the first time.
533 * @see Dali::Accessibility::Bridge::DisableAutoInit
534 * @see Dali::Accessibility::Bridge::AddTopLevelWindow
535 * @see Dali::Accessibility::Bridge::SetApplicationName
537 static void EnableAutoInit();
540 * @brief Encodes a widget ID as a usable bus name.
542 * @param widgetInstanceId The instance ID of a widget
543 * @return std::string Encoded bus name
545 * @see SetPreferredBusName
547 static std::string MakeBusNameForWidget(std::string_view widgetInstanceId);
549 static Signal<void()>& EnabledSignal()
551 return mEnabledSignal;
554 static Signal<void()>& DisabledSignal()
556 return mDisabledSignal;
559 static Signal<void()>& ScreenReaderEnabledSignal()
561 return mScreenReaderEnabledSignal;
564 static Signal<void()>& ScreenReaderDisabledSignal()
566 return mScreenReaderDisabledSignal;
572 std::unordered_set<const Accessible*> mKnownObjects;
573 std::string mBusName;
574 Bridge* mBridge = nullptr;
575 Actor mHighlightActor;
576 Actor mCurrentlyHighlightedActor;
577 std::pair<std::int32_t, std::int32_t> mExtentsOffset{0, 0};
579 std::shared_ptr<Data> mData;
580 friend class Accessible;
582 enum class AutoInitState
588 inline static AutoInitState mAutoInitState = AutoInitState::ENABLED;
590 inline static Signal<void()> mEnabledSignal;
591 inline static Signal<void()> mDisabledSignal;
592 inline static Signal<void()> mScreenReaderEnabledSignal;
593 inline static Signal<void()> mScreenReaderDisabledSignal;
596 * @brief Registers accessible object to be known in bridge object.
598 * Bridge must known about all currently alive accessible objects, as some requst
599 * might come and object will be identified by number id (it's memory address).
600 * To avoid memory corruption number id is checked against set of known objects.
602 * @param[in] object The accessible object
604 void RegisterOnBridge(const Accessible* object);
607 * @brief Tells bridge, that given object is considered root (doesn't have any parents).
609 * All root objects will have the same parent - application object. Application object
610 * is controlled by bridge and private.
612 * @param[in] owner The accessible object
614 void SetIsOnRootLevel(Accessible* owner);
618 * @brief Checks if ATSPI is activated or not.
619 * @return True if ATSPI is activated.
623 if(Bridge::GetCurrentBridge() == nullptr)
628 if(Bridge::GetCurrentBridge()->IsEnabled() == false)
633 return Bridge::GetCurrentBridge()->IsUp();
636 } // namespace Accessibility
639 #endif // DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H