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