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