[Tizen][AT-SPI] do not keep window in ApplicationAccessible
[platform/core/uifw/dali-adaptor.git] / dali / internal / accessibility / bridge / bridge-base.h
1 #ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
2 #define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_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/dali-adaptor-version.h>
23 #include <dali/public-api/signals/connection-tracker.h>
24 #include <dali/public-api/actors/layer.h>
25 #include <memory>
26
27 // INTERNAL INCLUDES
28 #include <dali/devel-api/adaptor-framework/window-devel.h>
29 #include <dali/internal/accessibility/bridge/accessibility-common.h>
30
31 /**
32  * @brief The AppAccessible class is to define Accessibility Application.
33  */
34 class AppAccessible : public virtual Dali::Accessibility::Accessible, public virtual Dali::Accessibility::Collection, public virtual Dali::Accessibility::Application
35 {
36 public:
37   Dali::Accessibility::EmptyAccessibleWithAddress mParent;
38   std::vector<Dali::Accessibility::Accessible*>   mChildren;
39   std::string                                     mName;
40
41   std::string GetName() override
42   {
43     return mName;
44   }
45
46   std::string GetDescription() override
47   {
48     return "";
49   }
50
51   Dali::Accessibility::Accessible* GetParent() override
52   {
53     return &mParent;
54   }
55
56   size_t GetChildCount() override
57   {
58     return mChildren.size();
59   }
60
61   Dali::Accessibility::Accessible* GetChildAtIndex(size_t index) override
62   {
63     auto size = mChildren.size();
64     if(index >= size)
65     {
66       throw std::domain_error{"invalid index " + std::to_string(index) + " for object with " + std::to_string(size) + " children"};
67     }
68     return mChildren[index];
69   }
70
71   size_t GetIndexInParent() override
72   {
73     throw std::domain_error{"can't call GetIndexInParent on application object"};
74   }
75
76   Dali::Accessibility::Role GetRole() override
77   {
78     return Dali::Accessibility::Role::APPLICATION;
79   }
80
81   Dali::Accessibility::States GetStates() override
82   {
83     return {};
84   }
85
86   Dali::Accessibility::Attributes GetAttributes() override
87   {
88     return {};
89   }
90
91   /**
92    * @brief Gets the Accessible object from the window.
93    *
94    * @param[in] window The window to find
95    * @return Null if mChildren is empty, otherwise the Accessible object
96    * @note Currently, the default window would be returned when mChildren is not empty.
97    */
98   Dali::Accessibility::Accessible* GetWindowAccessible(Dali::Window window)
99   {
100     if(mChildren.empty())
101     {
102       return nullptr;
103     }
104
105     Dali::Layer rootLayer = window.GetRootLayer();
106
107     // Find a child which is related to the window.
108     for(auto i = 0u; i < mChildren.size(); ++i)
109     {
110       if(rootLayer == mChildren[i]->GetInternalActor())
111       {
112         return mChildren[i];
113       }
114     }
115
116     // If can't find its children, return the default window.
117     return mChildren[0];
118   }
119
120   bool DoGesture(const Dali::Accessibility::GestureInfo& gestureInfo) override
121   {
122     return false;
123   }
124
125   std::vector<Dali::Accessibility::Relation> GetRelationSet() override
126   {
127     return {};
128   }
129
130   Dali::Actor GetInternalActor() override
131   {
132     return Dali::Actor{};
133   }
134
135   Dali::Accessibility::Address GetAddress() override
136   {
137     return {"", "root"};
138   }
139
140   std::string GetToolkitName() override
141   {
142     return {"dali"};
143   }
144
145   std::string GetVersion() override
146   {
147     return std::to_string(Dali::ADAPTOR_MAJOR_VERSION) + "." + std::to_string(Dali::ADAPTOR_MINOR_VERSION);
148   }
149 };
150
151 /**
152  * @brief Enumeration for FilteredEvents.
153  */
154 enum class FilteredEvents
155 {
156   BOUNDS_CHANGED ///< Bounds changed
157 };
158
159 // Custom specialization of std::hash
160 namespace std
161 {
162 template<>
163 struct hash<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>>
164 {
165   size_t operator()(std::pair<FilteredEvents, Dali::Accessibility::Accessible*> value) const
166   {
167     return (static_cast<size_t>(value.first) * 131) ^ reinterpret_cast<size_t>(value.second);
168   }
169 };
170 } // namespace std
171
172 /**
173  * @brief The BridgeBase class is basic class for Bridge functions.
174  */
175 class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
176 {
177   std::unordered_map<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>, std::pair<unsigned int, std::function<void()>>> mFilteredEvents;
178
179   /**
180    * @brief Removes all FilteredEvents using Tick signal.
181    *
182    * @return False if mFilteredEvents is empty, otherwise true.
183    */
184   bool TickFilteredEvents();
185
186 public:
187   /**
188    * @brief Adds FilteredEvents, Accessible, and delay time to mFilteredEvents.
189    *
190    * @param[in] kind FilteredEvents enum value
191    * @param[in] obj Accessible object
192    * @param[in] delay The delay time
193    * @param[in] functor The function to be called // NEED TO UPDATE!
194    */
195   void AddFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
196
197   /**
198    * @brief Callback when the visibility of the window is changed.
199    *
200    * @param[in] window The window to be changed
201    * @param[in] visible The visibility of the window
202    */
203   void OnWindowVisibilityChanged(Dali::Window window, bool visible);
204
205   /**
206    * @brief Callback when the window focus is changed.
207    *
208    * @param[in] window The window whose focus is changed
209    * @param[in] focusIn Whether the focus is in/out
210    */
211   void OnWindowFocusChanged(Dali::Window window, bool focusIn);
212
213   /**
214    * @copydoc Dali::Accessibility::Bridge::GetBusName()
215    */
216   const std::string& GetBusName() const override;
217
218   /**
219    * @copydoc Dali::Accessibility::Bridge::AddTopLevelWindow()
220    */
221   void AddTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
222
223   /**
224    * @copydoc Dali::Accessibility::Bridge::RemoveTopLevelWindow()
225    */
226   void RemoveTopLevelWindow(Dali::Accessibility::Accessible* windowAccessible) override;
227
228   /**
229    * @copydoc Dali::Accessibility::Bridge::AddPopup()
230    */
231   void AddPopup(Dali::Accessibility::Accessible* object) override;
232
233   /**
234    * @copydoc Dali::Accessibility::Bridge::RemovePopup()
235    */
236   void RemovePopup(Dali::Accessibility::Accessible* object) override;
237
238   /**
239    * @copydoc Dali::Accessibility::Bridge::GetApplication()
240    */
241   Dali::Accessibility::Accessible* GetApplication() const override
242   {
243     return &mApplication;
244   }
245
246   /**
247    * @brief Adds function to dbus interface.
248    */
249   template<typename SELF, typename... RET, typename... ARGS>
250   void AddFunctionToInterface(
251     DBus::DBusInterfaceDescription& desc, const std::string& funcName, DBus::ValueOrError<RET...> (SELF::*funcPtr)(ARGS...))
252   {
253     if(auto self = dynamic_cast<SELF*>(this))
254       desc.addMethod<DBus::ValueOrError<RET...>(ARGS...)>(
255         funcName,
256         [=](ARGS... args) -> DBus::ValueOrError<RET...> {
257           try
258           {
259             return (self->*funcPtr)(std::move(args)...);
260           }
261           catch(std::domain_error& e)
262           {
263             return DBus::Error{e.what()};
264           }
265         });
266   }
267
268   /**
269    * @brief Adds 'Get' property to dbus interface.
270    */
271   template<typename T, typename SELF>
272   void AddGetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
273                                  const std::string&              funcName,
274                                  T (SELF::*funcPtr)())
275   {
276     if(auto self = dynamic_cast<SELF*>(this))
277       desc.addProperty<T>(funcName,
278                           [=]() -> DBus::ValueOrError<T> {
279                             try
280                             {
281                               return (self->*funcPtr)();
282                             }
283                             catch(std::domain_error& e)
284                             {
285                               return DBus::Error{e.what()};
286                             }
287                           },
288                           {});
289   }
290
291   /**
292    * @brief Adds 'Set' property to dbus interface.
293    */
294   template<typename T, typename SELF>
295   void AddSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
296                                  const std::string&              funcName,
297                                  void (SELF::*funcPtr)(T))
298   {
299     if(auto self = dynamic_cast<SELF*>(this))
300       desc.addProperty<T>(funcName, {}, [=](T t) -> DBus::ValueOrError<void> {
301         try
302         {
303           (self->*funcPtr)(std::move(t));
304           return {};
305         }
306         catch(std::domain_error& e)
307         {
308           return DBus::Error{e.what()};
309         }
310       });
311   }
312
313   /**
314    * @brief Adds 'Set' and 'Get' properties to dbus interface.
315    */
316   template<typename T, typename T1, typename SELF>
317   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
318                                     const std::string&              funcName,
319                                     T1 (SELF::*funcPtrGet)(),
320                                     DBus::ValueOrError<void> (SELF::*funcPtrSet)(T))
321   {
322     if(auto self = dynamic_cast<SELF*>(this))
323       desc.addProperty<T>(
324         funcName,
325         [=]() -> DBus::ValueOrError<T> {
326           try
327           {
328             return (self->*funcPtrGet)();
329           }
330           catch(std::domain_error& e)
331           {
332             return DBus::Error{e.what()};
333           }
334         },
335         [=](T t) -> DBus::ValueOrError<void> {
336           try
337           {
338             (self->*funcPtrSet)(std::move(t));
339             return {};
340           }
341           catch(std::domain_error& e)
342           {
343             return DBus::Error{e.what()};
344           }
345         });
346   }
347
348   /**
349    * @brief Adds 'Get' and 'Set' properties to dbus interface.
350    */
351   template<typename T, typename T1, typename SELF>
352   void AddGetSetPropertyToInterface(DBus::DBusInterfaceDescription& desc,
353                                     const std::string&              funcName,
354                                     T1 (SELF::*funcPtrGet)(),
355                                     void (SELF::*funcPtrSet)(T))
356   {
357     if(auto self = dynamic_cast<SELF*>(this))
358       desc.addProperty<T>(
359         funcName,
360         [=]() -> DBus::ValueOrError<T> {
361           try
362           {
363             return (self->*funcPtrGet)();
364           }
365           catch(std::domain_error& e)
366           {
367             return DBus::Error{e.what()};
368           }
369         },
370         [=](T t) -> DBus::ValueOrError<void> {
371           try
372           {
373             (self->*funcPtrSet)(std::move(t));
374             return {};
375           }
376           catch(std::domain_error& e)
377           {
378             return DBus::Error{e.what()};
379           }
380         });
381   }
382
383   /**
384    * @brief Gets the string of the path excluding the specified prefix.
385    *
386    * @param path The path to get
387    * @return The string stripped of the specific prefix
388    */
389   static std::string StripPrefix(const std::string& path);
390
391   /**
392    * @brief Finds the Accessible object according to the path.
393    *
394    * @param[in] path The path for Accessible object
395    * @return The Accessible object corresponding to the path
396    */
397   Dali::Accessibility::Accessible* Find(const std::string& path) const;
398
399   /**
400    * @brief Finds the Accessible object with the given address.
401    *
402    * @param[in] ptr The unique Address of the object
403    * @return The Accessible object corresponding to the path
404    */
405   Dali::Accessibility::Accessible* Find(const Dali::Accessibility::Address& ptr) const;
406
407   /**
408    * @brief Returns the target object of the currently executed DBus method call.
409    *
410    * And any subclasses redefine `FindSelf` with a different return type as a convenient wrapper around dynamic_cast.
411    * @return The Accessible object
412    * @note When a DBus method is called on some object, this target object (`currentObject`) is temporarily saved by the bridge,
413    * because DBus handles the invocation target separately from the method arguments.
414    * We then use the saved object inside the 'glue' method (e.g. BridgeValue::GetMinimum)
415    * to call the equivalent method on the respective C++ object (this could be ScrollBar::AccessibleImpl::GetMinimum in the example given).
416    */
417   Dali::Accessibility::Accessible* FindSelf() const;
418
419   /**
420    * @copydoc Dali::Accessibility::Bridge::FindByPath()
421    */
422   Dali::Accessibility::Accessible* FindByPath(const std::string& name) const override;
423
424   /**
425    * @copydoc Dali::Accessibility::Bridge::SetApplicationName()
426    */
427   void SetApplicationName(std::string name) override
428   {
429     mApplication.mName = std::move(name);
430   }
431
432 protected:
433   mutable AppAccessible                         mApplication;
434   std::vector<Dali::Accessibility::Accessible*> mPopups;
435   bool                                          mIsScreenReaderSuppressed = false;
436
437 private:
438
439   /**
440    * @brief Sets an ID.
441    * @param[in] id An ID (integer value)
442    */
443   void SetId(int id);
444
445   /**
446    * @brief Gets the ID.
447    * @return The ID to be set
448    */
449   int GetId();
450
451   /**
452    * @brief Update registered events.
453    */
454   void UpdateRegisteredEvents();
455
456   using CacheElementType = std::tuple<
457     Dali::Accessibility::Address,
458     Dali::Accessibility::Address,
459     Dali::Accessibility::Address,
460     std::vector<Dali::Accessibility::Address>,
461     std::vector<std::string>,
462     std::string,
463     Dali::Accessibility::Role,
464     std::string,
465     std::array<uint32_t, 2>>;
466
467   /**
468    * @brief Gets Items  // NEED TO UPDATE!
469    *
470    * @return
471    */
472   DBus::ValueOrError<std::vector<CacheElementType>> GetItems();
473
474   /**
475    * @brief Creates CacheElement.
476    *
477    * CreateCacheElement method works for GetItems which is a part of ATSPI protocol.
478    * ATSPI client library (libatspi from at-spi2-core) depending on cacheing policy configuration uses GetItems
479    * to pre-load entire accessible tree from application to its own cache in single dbus call.
480    * Otherwise the particular nodes in a tree are cached lazily when client library tries to access them.
481    * @param item Accessible to get information
482    * @return The elements to be cached
483    */
484   CacheElementType CreateCacheElement(Dali::Accessibility::Accessible* item);
485
486 protected:
487   BridgeBase();
488   virtual ~BridgeBase();
489
490   /**
491    * @copydoc Dali::Accessibility::Bridge::ForceUp()
492    */
493   ForceUpResult ForceUp() override;
494
495   /**
496    * @copydoc Dali::Accessibility::Bridge::ForceDown()
497    */
498   void ForceDown() override;
499
500   DBus::DBusServer           mDbusServer;
501   DBusWrapper::ConnectionPtr mConnectionPtr;
502   int                        mId = 0;
503   DBus::DBusClient           mRegistry;
504   bool                       IsBoundsChangedEventAllowed{false};
505 };
506
507 #endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H