Merge "Revert "[Tizen] Remove to call key consumed event in ATSPI bridge"" into tizen
[platform/core/uifw/dali-adaptor.git] / dali / devel-api / adaptor-framework / accessibility-bridge.h
1 #ifndef DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
2 #define DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
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
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <dali/public-api/actors/actor.h>
23 #include <dali/public-api/math/rect.h>
24 #include <functional>
25 #include <memory>
26 #include <stdexcept>
27 #include <string>
28 #include <unordered_set>
29
30 // INTERNAL INCLUDES
31 #include <dali/devel-api/adaptor-framework/accessibility.h>
32 #include <dali/public-api/adaptor-framework/window.h>
33
34 namespace Dali
35 {
36 namespace Accessibility
37 {
38 class Accessible;
39 class ProxyAccessible;
40
41 /**
42  * @brief Base class for different accessibility bridges.
43  *
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.
47  *
48  * @note This class is singleton.
49  */
50 struct DALI_ADAPTOR_API Bridge
51 {
52   enum class ForceUpResult
53   {
54     JUST_STARTED,
55     ALREADY_UP,
56     FAILED
57   };
58
59   /**
60    * @brief Destructor
61    */
62   virtual ~Bridge() = default;
63
64   /**
65    * @brief Gets bus name which bridge is initialized on.
66    *
67    * @return The bus name
68    */
69   virtual const std::string& GetBusName() const = 0;
70
71   /**
72    * @brief Registers top level window.
73    *
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.
78    *
79    * @param[in] object The accessible object
80    */
81   virtual void AddTopLevelWindow(Accessible* object) = 0;
82
83   /**
84    * @brief Removes top level window.
85    *
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.
89    *
90    * @param[in] object The accessible object
91    */
92   virtual void RemoveTopLevelWindow(Accessible* object) = 0;
93
94   /**
95    * @brief Adds object on the top of the stack of "default label" sourcing objects.
96    *
97    * @see GetDefaultLabel
98    *
99    * @param[in] object The accessible object
100    */
101   virtual void RegisterDefaultLabel(Accessible* object) = 0;
102
103   /**
104    * @brief Removes object from the stack of "default label" sourcing objects.
105    *
106    * @see GetDefaultLabel
107    *
108    * @param[in] object The accessible object
109    */
110   virtual void UnregisterDefaultLabel(Accessible* object) = 0;
111
112   /**
113    * @brief Gets the top-most object from the stack of "default label" sourcing objects.
114    *
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.
118    *
119    * @param[in] root The root of the navigation context for which to retrieve the default label.
120    *
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".
127    */
128   virtual Accessible* GetDefaultLabel(Accessible* root) const = 0;
129
130   /**
131    * @brief Sets name of current application which will be visible on accessibility bus.
132    *
133    * @param[in] name The application name
134    */
135   virtual void SetApplicationName(std::string name) = 0;
136
137   /**
138    * @brief Sets the name of the GUI toolkit that AT-SPI clients can query.
139    *
140    * The default name is "dali".
141    *
142    * @param toolkitName The toolkit name
143    */
144   virtual void SetToolkitName(std::string_view toolkitName) = 0;
145
146   /**
147    * @brief Gets object being root of accessibility tree.
148    *
149    * @return handler to accessibility object
150    */
151   virtual Accessible* GetApplication() const = 0;
152
153   /**
154    * @brief Finds an object in accessibility tree.
155    *
156    * @param[in] path The path to object
157    *
158    * @return The handler to accessibility object
159    */
160   virtual Accessible* FindByPath(const std::string& path) const = 0;
161
162   /**
163    * @brief Notifies accessibility dbus that window has just been created.
164    *
165    * @param[in] window The window to be created
166    */
167   virtual void WindowCreated(Window window) = 0;
168
169   /**
170    * @brief Notifies accessibility dbus that window has just been shown.
171    *
172    * @param[in] window The window to be shown
173    */
174   virtual void WindowShown(Window window) = 0;
175
176   /**
177    * @brief Notifies accessibility dbus that window has just been hidden.
178    *
179    * @param[in] window The window to be hidden
180    */
181   virtual void WindowHidden(Window window) = 0;
182
183   /**
184    * @brief Notifies accessibility dbus that window has just been focused.
185    *
186    * @param[in] window The window to be focused
187    */
188   virtual void WindowFocused(Window window) = 0;
189
190   /**
191    * @brief Notifies accessibility dbus that window has just been out of focus.
192    *
193    * @param[in] window The window to be out of focus
194    */
195   virtual void WindowUnfocused(Window window) = 0;
196
197   /**
198    * @brief Notifies accessibility dbus that window has just been minimized.
199    *
200    * @param[in] window The window to be minimized
201    */
202   virtual void WindowMinimized(Window window) = 0;
203
204   /**
205    * @brief Notifies accessibility dbus that window has just been restored.
206    *
207    * @param[in] window The window to be restored
208    * @param[in] detail Restored window state
209    */
210   virtual void WindowRestored(Window window, WindowRestoreType detail) = 0;
211
212   /**
213    * @brief Notifies accessibility dbus that window has just been maximized.
214    *
215    * @param[in] window The window to be maximized
216    */
217   virtual void WindowMaximized(Window window) = 0;
218
219   /**
220    * @brief Initializes accessibility bus.
221    */
222   virtual void Initialize() = 0;
223
224   /**
225    * @brief Terminates accessibility bus.
226    */
227   virtual void Terminate() = 0;
228
229   /**
230    * @brief This method is called, when bridge is being activated.
231    */
232   virtual ForceUpResult ForceUp()
233   {
234     if(mData)
235     {
236       return ForceUpResult::ALREADY_UP;
237     }
238     mData          = std::make_shared<Data>();
239     mData->mBridge = this;
240     return ForceUpResult::JUST_STARTED;
241   }
242
243   /**
244    * @brief This method is called, when bridge is being deactivated.
245    */
246   virtual void ForceDown() = 0;
247
248   /**
249    * @brief Checks if bridge is activated or not.
250    * @return True if brige is activated.
251    */
252   bool IsUp() const
253   {
254     return bool(mData);
255   }
256
257   /**
258    * @brief Emits cursor-moved event on at-spi bus.
259    *
260    * @param[in] obj The accessible object
261    * @param[in] cursorPosition The new cursor position
262    **/
263   virtual void EmitCursorMoved(Accessible* obj, unsigned int cursorPosition) = 0;
264
265   /**
266    * @brief Emits active-descendant-changed event on at-spi bus.
267    *
268    * @param[in] obj The accessible object
269    * @param[in] child The child of the object
270    **/
271   virtual void EmitActiveDescendantChanged(Accessible* obj, Accessible* child) = 0;
272
273   /**
274    * @brief Emits text-changed event on at-spi bus.
275    *
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
281    **/
282   virtual void EmitTextChanged(Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string& content) = 0;
283
284   /**
285    * @brief Emits MoveOuted event on at-spi bus.
286    *
287    * @param[in] obj Accessible object
288    * @param[in] type Direction type when an Accessible object moves out of screen
289    **/
290   virtual void EmitMovedOutOfScreen(Accessible* obj, ScreenRelativeMoveType type) = 0;
291
292   /**
293    * @brief Emits "org.a11y.atspi.Socket.Available" event on AT-SPI bus.
294    *
295    * @param obj Accessible object
296    */
297   virtual void EmitSocketAvailable(Accessible* obj) = 0;
298
299   /**
300    * @brief Emits ScrollStarted event on at-spi bus.
301    *
302    * @param obj Accessible Object
303    */
304   virtual void EmitScrollStarted(Accessible *obj) = 0;
305
306     /**
307    * @brief Emits ScrollFinished event on at-spi bus.
308    *
309    * @param obj Accessible Object
310    */
311   virtual void EmitScrollFinished(Accessible *obj) = 0;
312
313   /**
314    * @brief Emits state-changed event on at-spi bus.
315    *
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)
320    **/
321   virtual void EmitStateChanged(Accessible* obj, State state, int newValue, int reserved = 0) = 0;
322
323   /**
324    * @brief Emits window event on at-spi bus.
325    *
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
329    **/
330   virtual void Emit(Accessible* obj, WindowEvent event, unsigned int detail = 0) = 0;
331
332   /**
333    * @brief Emits property-changed event on at-spi bus.
334    *
335    * @param[in] obj The accessible object
336    * @param[in] event Property changed event
337    **/
338   virtual void Emit(Accessible* obj, ObjectPropertyChangeEvent event) = 0;
339
340   /**
341    * @brief Emits bounds-changed event on at-spi bus.
342    *
343    * @param[in] obj The accessible object
344    * @param[in] rect The rectangle for changed bounds
345    **/
346   virtual void EmitBoundsChanged(Accessible* obj, Rect<> rect) = 0;
347
348   /**
349    * @brief Emits org.a11y.atspi.Event.Window.PostRender on the AT-SPI bus.
350    *
351    * @param[in] obj The Accessible sender object
352    *
353    * The sender of this event is expected to be an Accessible object that
354    * represents a top-level window.
355    *
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.
358    */
359   virtual void EmitPostRender(Accessible *obj) = 0;
360
361   /**
362    * @brief Emits key event on at-spi bus.
363    *
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.
366    *
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
373    **/
374   virtual Consumed Emit(KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText) = 0;
375
376   /**
377    * @brief Reads given text by screen reader
378    *
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
386    */
387   virtual void Say(const std::string& text, bool discardable, std::function<void(std::string)> callback) = 0;
388
389   /**
390    * @brief Force accessibility client to pause.
391    */
392   virtual void Pause() = 0;
393
394   /**
395    * @brief Force accessibility client to resume.
396    */
397   virtual void Resume() = 0;
398
399   /**
400    * @brief Cancels anything screen-reader is reading / has queued to read
401    *
402    * @param[in] alsoNonDiscardable whether to cancel non-discardable readings as well
403    */
404   virtual void StopReading(bool alsoNonDiscardable) = 0;
405
406   /**
407    * @brief Suppresses reading of screen-reader
408    *
409    * @param[in] suppress whether to suppress reading of screen-reader
410    */
411   virtual void SuppressScreenReader(bool suppress) = 0;
412
413   /**
414    * @brief Gets screen reader status.
415    *
416    * @return True if screen reader is enabled
417    */
418   virtual bool GetScreenReaderEnabled() = 0;
419
420   /**
421    * @brief Gets ATSPI status.
422    *
423    * @return True if ATSPI is enabled
424    */
425   virtual bool IsEnabled() = 0;
426
427   /**
428    * @brief Calls socket.Embed(plug) via D-Bus.
429    *
430    * @param[in] plug The plug
431    * @param[in] socket The socket
432    *
433    * @return Address returned by the D-Bus call.
434    *
435    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
436    * @see UnembedSocket()
437    */
438   virtual Address EmbedSocket(const Address& plug, const Address& socket) = 0;
439
440   /**
441    * @brief Calls socket.Embedded(plug) via D-Bus.
442    *
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.
445    *
446    * @param[in] plug The plug
447    * @param[in] socket The socket
448    */
449   virtual void EmbedAtkSocket(const Address& plug, const Address& socket) = 0;
450
451   /**
452    * @brief Calls socket.Unmbed(plug) via D-Bus.
453    *
454    * @param[in] plug The plug
455    * @param[in] socket The socket
456    *
457    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
458    * @see EmbedSocket()
459    */
460   virtual void UnembedSocket(const Address& plug, const Address& socket) = 0;
461
462   /**
463    * @brief Calls socket.SetOffset(x, y) via D-Bus.
464    *
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.
467    *
468    * @param[in] socket The socket
469    * @param[in] x Horizontal offset
470    * @param[in] y Vertical offset
471    *
472    * @note Remote object pointed to by 'socket' must implement 'org.a11y.atspi.Socket'.
473    * @see EmbedSocket()
474    * @see SetExtentsOffset()
475    */
476   virtual void SetSocketOffset(ProxyAccessible* socket, std::int32_t x, std::int32_t y) = 0;
477
478   /**
479    * @brief Sets the global extents offset.
480    *
481    * This offset will be added during serialization of GetExtents() return value to D-Bus.
482    * Local calls to GetExtents() are unaffected.
483    *
484    * @param[in] x Horizontal offset
485    * @param[in] y Vertical offset
486    *
487    * @see SetSocketOffset()
488    * @see Dali::Accessibility::Component::GetExtents()
489    */
490   virtual void SetExtentsOffset(std::int32_t x, std::int32_t y) = 0;
491
492   /**
493    * @brief Sets the preferred bus name.
494    *
495    * If the Bridge is enabled, it will immediately release the previous name and request the new one.
496    *
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.
499    *
500    * @param preferredBusName The preferred bus name
501    */
502   virtual void SetPreferredBusName(std::string_view preferredBusName) = 0;
503
504   /**
505    * @brief Returns instance of bridge singleton object.
506    *
507    * @return The current bridge object
508    **/
509   static std::shared_ptr<Bridge> GetCurrentBridge();
510
511   /**
512    * @brief Blocks auto-initialization of AT-SPI bridge
513    *
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.
517    *
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.
521    *
522    * @see Dali::Accessibility::DummyBridge
523    * @see Dali::Accessibility::Bridge::EnableAutoInit
524    */
525   static void DisableAutoInit();
526
527   /**
528    * @brief Re-enables auto-initialization of AT-SPI bridge
529    *
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.
532    *
533    * @see Dali::Accessibility::Bridge::DisableAutoInit
534    * @see Dali::Accessibility::Bridge::AddTopLevelWindow
535    * @see Dali::Accessibility::Bridge::SetApplicationName
536    */
537   static void EnableAutoInit();
538
539   /**
540    * @brief Encodes a widget ID as a usable bus name.
541    *
542    * @param widgetInstanceId The instance ID of a widget
543    * @return std::string Encoded bus name
544    *
545    * @see SetPreferredBusName
546    */
547   static std::string MakeBusNameForWidget(std::string_view widgetInstanceId);
548
549   static Signal<void()>& EnabledSignal()
550   {
551     return mEnabledSignal;
552   }
553
554   static Signal<void()>& DisabledSignal()
555   {
556     return mDisabledSignal;
557   }
558
559   static Signal<void()>& ScreenReaderEnabledSignal()
560   {
561     return mScreenReaderEnabledSignal;
562   }
563
564   static Signal<void()>& ScreenReaderDisabledSignal()
565   {
566     return mScreenReaderDisabledSignal;
567   }
568
569 protected:
570   struct Data
571   {
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};
578   };
579   std::shared_ptr<Data> mData;
580   friend class Accessible;
581
582   enum class AutoInitState
583   {
584     DISABLED,
585     ENABLED
586   };
587
588   inline static AutoInitState mAutoInitState = AutoInitState::ENABLED;
589
590   inline static Signal<void()> mEnabledSignal;
591   inline static Signal<void()> mDisabledSignal;
592   inline static Signal<void()> mScreenReaderEnabledSignal;
593   inline static Signal<void()> mScreenReaderDisabledSignal;
594
595   /**
596    * @brief Registers accessible object to be known in bridge object.
597    *
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.
601    *
602    * @param[in] object The accessible object
603    **/
604   void RegisterOnBridge(const Accessible* object);
605
606   /**
607    * @brief Tells bridge, that given object is considered root (doesn't have any parents).
608    *
609    * All root objects will have the same parent - application object. Application object
610    * is controlled by bridge and private.
611    *
612    * @param[in] owner The accessible object
613    **/
614   void SetIsOnRootLevel(Accessible* owner);
615 };
616
617 /**
618  * @brief Checks if ATSPI is activated or not.
619  * @return True if ATSPI is activated.
620  */
621 inline bool IsUp()
622 {
623   if(Bridge::GetCurrentBridge() == nullptr)
624   {
625     return false;
626   }
627
628   if(Bridge::GetCurrentBridge()->IsEnabled() == false)
629   {
630     return false;
631   }
632
633   return Bridge::GetCurrentBridge()->IsUp();
634 }
635
636 } // namespace Accessibility
637 } // namespace Dali
638
639 #endif // DALI_ADAPTOR_ACCESSIBILITY_BRIDGE_H