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