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